perchai-cli 2.4.21 → 2.4.23
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 +832 -40
- package/package.json +1 -1
package/dist/perch.mjs
CHANGED
|
@@ -85560,7 +85560,6 @@ Final answers lead with findings, name artifacts or delivery status, and give on
|
|
|
85560
85560
|
var MARKET_DESK_TOOL_NAMES;
|
|
85561
85561
|
var init_marketDeskAccess = __esm({
|
|
85562
85562
|
"features/perchTerminal/runtime/marketDesk/marketDeskAccess.ts"() {
|
|
85563
|
-
"use strict";
|
|
85564
85563
|
init_toolNames();
|
|
85565
85564
|
MARKET_DESK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
85566
85565
|
TOOL_NAMES.getMarketSignal,
|
|
@@ -86717,7 +86716,7 @@ var init_managedWorkflowRegistry = __esm({
|
|
|
86717
86716
|
"name": "AP Suite Publisher",
|
|
86718
86717
|
"description": "Publishes the final AP operator suite envelope from analyst output. Writes findings CSV and report to the output folder.",
|
|
86719
86718
|
"lane": "writer",
|
|
86720
|
-
"systemPrompt": '# AP Suite Publisher\n\nYou receive the analyst\'s structured output from the deterministic AP extraction. Your job is to write deliverable files to disk and return their paths \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `findings.csv`** \u2014 one row per finding from `priorOutput.sandboxArtifact.findings` + analyst `thematicBlocks`:\n```\nid,severity,category,title,financial_exposure,evidence\nfinding-1,critical,duplicate_invoice,"INV-88421 matches INV-77209 same vendor same amount",12400,invoices/INV-88421.csv\n```\n\n**2. `report.md`** \u2014 a structured markdown report:\n```markdown\n# AP Audit Report \u2014 {folderPath leaf}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary \u2014 2\u20134 sentences, verbatim from analyst output}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## Findings ({N} total)\n{For each thematic block: ### {title}, severity badge, narrative, finding IDs}\n\n## Recommendations\n{Numbered list from analyst recommendations}\n\n## Data Coverage\n- Records processed: {metrics.recordsNormalized}\n- Tables loaded: {metrics.tablesLoaded}\n- Findings: {metrics.findingsCount}\n{warnings if any}\n```\n\n## Rules\n\n1. **Write the files first, return the paths.** Don\'t summarize in your response \u2014 the files are the deliverable.\n2. Use the folderPath from context. If it\'s not in priorOutput, use the folder name you can infer from evidence paths.\n3. Never fabricate findings not in `sandboxArtifact` or analyst output.\n4. If `sandboxArtifact` is null or analyst output is empty, write a report.md explaining what failed and why.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "findings": "{folderPath}/perch-output/findings.csv",\n "report": "{folderPath}/perch-output/report.md"\n },\n "findingsCount": 0,\n "topFinding": "string or null"\n}\n```\n\n---\n\n
|
|
86719
|
+
"systemPrompt": '# AP Suite Publisher\n\nYou receive the analyst\'s structured output from the deterministic AP extraction. Your job is to write deliverable files to disk and return their paths \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `findings.csv`** \u2014 one row per finding from `priorOutput.sandboxArtifact.findings` + analyst `thematicBlocks`:\n```\nid,severity,category,title,financial_exposure,evidence\nfinding-1,critical,duplicate_invoice,"INV-88421 matches INV-77209 same vendor same amount",12400,invoices/INV-88421.csv\n```\n\n**2. `report.md`** \u2014 a structured markdown report:\n```markdown\n# AP Audit Report \u2014 {folderPath leaf}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary \u2014 2\u20134 sentences, verbatim from analyst output}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## Findings ({N} total)\n{For each thematic block: ### {title}, severity badge, narrative, finding IDs}\n\n## Recommendations\n{Numbered list from analyst recommendations}\n\n## Data Coverage\n- Records processed: {metrics.recordsNormalized}\n- Tables loaded: {metrics.tablesLoaded}\n- Findings: {metrics.findingsCount}\n{warnings if any}\n```\n\n## Rules\n\n1. **Write the files first, return the paths.** Don\'t summarize in your response \u2014 the files are the deliverable.\n2. Use the folderPath from context. If it\'s not in priorOutput, use the folder name you can infer from evidence paths.\n3. Never fabricate findings not in `sandboxArtifact` or analyst output.\n4. If `sandboxArtifact` is null or analyst output is empty, write a report.md explaining what failed and why.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "findings": "{folderPath}/perch-output/findings.csv",\n "report": "{folderPath}/perch-output/report.md"\n },\n "findingsCount": 0,\n "topFinding": "string or null"\n}\n```\n\n---\n\n# Core Perch skill: spreadsheets\n\n\n# spreadsheets\n\nUse this skill when the user asks for a spreadsheet artifact, spreadsheet inspection, import-ready CSV, formulas, reconciliation tabs, exception tabs, or workbook-quality output.\n\n## Operating Rules\n\n- Profile incoming sheets before changing them: row counts, columns, types, key IDs, totals, and empty fields.\n- Preserve identifiers as text when they are invoice numbers, account numbers, vendor IDs, employee IDs, tickers, or other non-math values.\n- Put source values on input tabs and formulas on analysis tabs when producing XLSX workbooks.\n- Add checks for totals, row counts, formulas, and exception counts when the workbook drives a decision.\n- Use deterministic code or workbook inspection for fragile calculations; do not hand-wave formula behavior.\n\n## Verification\n\nBefore delivery, verify that the file exists, formulas are present where expected, totals reconcile, and CSV exports keep exact values. See `references/workbook-quality.md`.\n\n---\n\n---\nname: csv-findings\ndescription: Produce clean findings CSV files that spreadsheet tools can open reliably.\n---\n\n# csv-findings\n\nUse this skill for required findings, exceptions, reconciliation, or signal CSV deliverables.\n\n## Output contract\n\n- Write CSV files to `{folderPath}/perch-output/`.\n- Use deterministic column order from the base prompt.\n- Return the CSV path in `outputFiles`.\n\n## How to build the CSV\n\nPrefer writing a small Python script to `/tmp/<workflow>-csv-findings.py` and running it with Bash when quoting, commas, newlines, or currency values could be tricky. Use the standard library `csv` module, create `{folderPath}/perch-output/`, and verify with `ls -l "{folderPath}/perch-output/"`.\n\n```python\nimport csv\nfrom pathlib import Path\n\nout_dir = Path(folder_path) / "perch-output"\nout_dir.mkdir(parents=True, exist_ok=True)\nwith (out_dir / "findings.csv").open("w", newline="", encoding="utf-8") as f:\n writer = csv.DictWriter(f, fieldnames=["id", "severity", "category", "title", "financial_exposure", "evidence"])\n writer.writeheader()\n writer.writerows(rows)\n```\n\n## Conventions\n\n- Preserve exact IDs, names, amounts, accounts, dates, and source filenames from the analyst or sandbox output.\n- Quote fields through the CSV writer; do not hand-escape rows.\n- Use blank cells for missing values rather than invented values.\n- If there are no findings, still write the header row.',
|
|
86721
86720
|
"allowedTools": [
|
|
86722
86721
|
"writeLocalFile",
|
|
86723
86722
|
"bash",
|
|
@@ -87024,7 +87023,7 @@ var init_managedWorkflowRegistry = __esm({
|
|
|
87024
87023
|
"name": "Earnings Publisher",
|
|
87025
87024
|
"description": "Writes the earnings review findings and memo to the output folder.",
|
|
87026
87025
|
"lane": "writer",
|
|
87027
|
-
"systemPrompt": '# Earnings Publisher\n\nYou receive the analyst\'s structured earnings output. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `earnings-findings.csv`** \u2014 key metrics and conflicts, one row per signal:\n```\ntype,metric,value,source,conflict,detail\nrevenue,Q1_2026,$125M,earnings-release.html,no,"Revenue $125M in-line"\nconflict,revenue,$412M vs $125M,transcript.txt vs release.html,yes,"Two sources disagree \u2014 transcript shows $412M"\nguidance,FY_2026,raised,call-transcript.md,no,"Guidance raised to $520M"\n```\n\n**2. `earnings-memo.md`** \u2014 analyst memo format:\n```markdown\n# Earnings Review \u2014 {company / folder name}\nGenerated: {ISO date}\n\n## Headline\n{1-sentence: period, revenue, beat/miss, guidance direction}\n\n## Key Metrics\n| Metric | Value | vs Consensus | Source |\n|--------|-------|--------------|--------|\n{rows from analyst output \u2014 exact figures}\n\n## Conflicts & Risk Signals\n{Any cross-source discrepancies with both values and file names}\n\n## Guidance\n{Changes, raised/lowered/withdrawn, exact figures}\n\n## Coverage\n{Files reviewed, any gaps}\n```\n\nThe `folderPath` is in `priorOutput.folderPath`.\n\n## Rules\n\n1. **Write files first, return paths.** The memo is what the analyst team reads \u2014 not a chat message.\n2. Revenue, EPS, and margin figures must be exact from analyst output \u2014 never round or paraphrase.\n3. If two sources disagree, include both values and both file names in the conflict row.\n4. Never fabricate signals not in the analyst output.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "findings": "{folderPath}/perch-output/earnings-findings.csv",\n "memo": "{folderPath}/perch-output/earnings-memo.md"\n },\n "keyMetric": "Revenue $125M, beat 3%",\n "conflictsFound": 0\n}\n```\n\n---\n\n
|
|
87026
|
+
"systemPrompt": '# Earnings Publisher\n\nYou receive the analyst\'s structured earnings output. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `earnings-findings.csv`** \u2014 key metrics and conflicts, one row per signal:\n```\ntype,metric,value,source,conflict,detail\nrevenue,Q1_2026,$125M,earnings-release.html,no,"Revenue $125M in-line"\nconflict,revenue,$412M vs $125M,transcript.txt vs release.html,yes,"Two sources disagree \u2014 transcript shows $412M"\nguidance,FY_2026,raised,call-transcript.md,no,"Guidance raised to $520M"\n```\n\n**2. `earnings-memo.md`** \u2014 analyst memo format:\n```markdown\n# Earnings Review \u2014 {company / folder name}\nGenerated: {ISO date}\n\n## Headline\n{1-sentence: period, revenue, beat/miss, guidance direction}\n\n## Key Metrics\n| Metric | Value | vs Consensus | Source |\n|--------|-------|--------------|--------|\n{rows from analyst output \u2014 exact figures}\n\n## Conflicts & Risk Signals\n{Any cross-source discrepancies with both values and file names}\n\n## Guidance\n{Changes, raised/lowered/withdrawn, exact figures}\n\n## Coverage\n{Files reviewed, any gaps}\n```\n\nThe `folderPath` is in `priorOutput.folderPath`.\n\n## Rules\n\n1. **Write files first, return paths.** The memo is what the analyst team reads \u2014 not a chat message.\n2. Revenue, EPS, and margin figures must be exact from analyst output \u2014 never round or paraphrase.\n3. If two sources disagree, include both values and both file names in the conflict row.\n4. Never fabricate signals not in the analyst output.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "findings": "{folderPath}/perch-output/earnings-findings.csv",\n "memo": "{folderPath}/perch-output/earnings-memo.md"\n },\n "keyMetric": "Revenue $125M, beat 3%",\n "conflictsFound": 0\n}\n```\n\n---\n\n# Core Perch skill: spreadsheets\n\n\n# spreadsheets\n\nUse this skill when the user asks for a spreadsheet artifact, spreadsheet inspection, import-ready CSV, formulas, reconciliation tabs, exception tabs, or workbook-quality output.\n\n## Operating Rules\n\n- Profile incoming sheets before changing them: row counts, columns, types, key IDs, totals, and empty fields.\n- Preserve identifiers as text when they are invoice numbers, account numbers, vendor IDs, employee IDs, tickers, or other non-math values.\n- Put source values on input tabs and formulas on analysis tabs when producing XLSX workbooks.\n- Add checks for totals, row counts, formulas, and exception counts when the workbook drives a decision.\n- Use deterministic code or workbook inspection for fragile calculations; do not hand-wave formula behavior.\n\n## Verification\n\nBefore delivery, verify that the file exists, formulas are present where expected, totals reconcile, and CSV exports keep exact values. See `references/workbook-quality.md`.\n\n---\n\n---\nname: csv-findings\ndescription: Produce clean findings CSV files that spreadsheet tools can open reliably.\n---\n\n# csv-findings\n\nUse this skill for required findings, exceptions, reconciliation, or signal CSV deliverables.\n\n## Output contract\n\n- Write CSV files to `{folderPath}/perch-output/`.\n- Use deterministic column order from the base prompt.\n- Return the CSV path in `outputFiles`.\n\n## How to build the CSV\n\nPrefer writing a small Python script to `/tmp/<workflow>-csv-findings.py` and running it with Bash when quoting, commas, newlines, or currency values could be tricky. Use the standard library `csv` module, create `{folderPath}/perch-output/`, and verify with `ls -l "{folderPath}/perch-output/"`.\n\n```python\nimport csv\nfrom pathlib import Path\n\nout_dir = Path(folder_path) / "perch-output"\nout_dir.mkdir(parents=True, exist_ok=True)\nwith (out_dir / "findings.csv").open("w", newline="", encoding="utf-8") as f:\n writer = csv.DictWriter(f, fieldnames=["id", "severity", "category", "title", "financial_exposure", "evidence"])\n writer.writeheader()\n writer.writerows(rows)\n```\n\n## Conventions\n\n- Preserve exact IDs, names, amounts, accounts, dates, and source filenames from the analyst or sandbox output.\n- Quote fields through the CSV writer; do not hand-escape rows.\n- Use blank cells for missing values rather than invented values.\n- If there are no findings, still write the header row.',
|
|
87028
87027
|
"allowedTools": [
|
|
87029
87028
|
"writeLocalFile",
|
|
87030
87029
|
"bash",
|
|
@@ -87183,7 +87182,7 @@ var init_managedWorkflowRegistry = __esm({
|
|
|
87183
87182
|
"name": "GL Resolver",
|
|
87184
87183
|
"description": "Receives the analyst output and writes the GL exception report to the output folder.",
|
|
87185
87184
|
"lane": "writer",
|
|
87186
|
-
"systemPrompt": '# GL Resolver\n\nYou receive the analyst\'s structured output from the deterministic GL reconciliation. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `gl-exceptions.csv`** \u2014 one row per finding:\n```\nid,severity,category,account,entry_id,financial_exposure,detail\ngl-suspense-1,high,suspense_aging,9999,,47500,"Account 9999 carries $47,500 balance"\ngl-unmatched-suspense-2,high,unmatched_suspense,9999,JE-2026-0315,47500,"JE-2026-0315 debits suspense with no offset"\n```\n\n**2. `gl-report.md`** \u2014 structured markdown:\n```markdown\n# GL Reconciliation Report \u2014 {folderPath leaf}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## Exception Detail\n{For each thematic block: ### {title}, findings with account IDs and entry IDs}\n\n## Recommended Actions\n{Numbered list \u2014 e.g. "Clear suspense 9999 by allocating JE-2026-0315 to cost center X"}\n\n## Coverage\n- Trial balance rows: {metrics.trialBalanceRows}\n- Journal entries: {metrics.journalEntryCount}\n- Suspense accounts: {metrics.suspenseAccountCount}\n```\n\n## Rules\n\n1. **Write files first, return paths.** The CSV is the deliverable \u2014 accounting needs to sort and filter it, not read a chat message.\n2. Account IDs and entry IDs must appear verbatim from the findings \u2014 don\'t paraphrase.\n3. Never fabricate breaks not in `sandboxArtifact`.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "exceptions": "{folderPath}/perch-output/gl-exceptions.csv",\n "report": "{folderPath}/perch-output/gl-report.md"\n },\n "exceptionsCount": 0,\n "topException": "string or null"\n}\n```\n\n---\n\n
|
|
87185
|
+
"systemPrompt": '# GL Resolver\n\nYou receive the analyst\'s structured output from the deterministic GL reconciliation. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `gl-exceptions.csv`** \u2014 one row per finding:\n```\nid,severity,category,account,entry_id,financial_exposure,detail\ngl-suspense-1,high,suspense_aging,9999,,47500,"Account 9999 carries $47,500 balance"\ngl-unmatched-suspense-2,high,unmatched_suspense,9999,JE-2026-0315,47500,"JE-2026-0315 debits suspense with no offset"\n```\n\n**2. `gl-report.md`** \u2014 structured markdown:\n```markdown\n# GL Reconciliation Report \u2014 {folderPath leaf}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## Exception Detail\n{For each thematic block: ### {title}, findings with account IDs and entry IDs}\n\n## Recommended Actions\n{Numbered list \u2014 e.g. "Clear suspense 9999 by allocating JE-2026-0315 to cost center X"}\n\n## Coverage\n- Trial balance rows: {metrics.trialBalanceRows}\n- Journal entries: {metrics.journalEntryCount}\n- Suspense accounts: {metrics.suspenseAccountCount}\n```\n\n## Rules\n\n1. **Write files first, return paths.** The CSV is the deliverable \u2014 accounting needs to sort and filter it, not read a chat message.\n2. Account IDs and entry IDs must appear verbatim from the findings \u2014 don\'t paraphrase.\n3. Never fabricate breaks not in `sandboxArtifact`.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "exceptions": "{folderPath}/perch-output/gl-exceptions.csv",\n "report": "{folderPath}/perch-output/gl-report.md"\n },\n "exceptionsCount": 0,\n "topException": "string or null"\n}\n```\n\n---\n\n# Core Perch skill: spreadsheets\n\n\n# spreadsheets\n\nUse this skill when the user asks for a spreadsheet artifact, spreadsheet inspection, import-ready CSV, formulas, reconciliation tabs, exception tabs, or workbook-quality output.\n\n## Operating Rules\n\n- Profile incoming sheets before changing them: row counts, columns, types, key IDs, totals, and empty fields.\n- Preserve identifiers as text when they are invoice numbers, account numbers, vendor IDs, employee IDs, tickers, or other non-math values.\n- Put source values on input tabs and formulas on analysis tabs when producing XLSX workbooks.\n- Add checks for totals, row counts, formulas, and exception counts when the workbook drives a decision.\n- Use deterministic code or workbook inspection for fragile calculations; do not hand-wave formula behavior.\n\n## Verification\n\nBefore delivery, verify that the file exists, formulas are present where expected, totals reconcile, and CSV exports keep exact values. See `references/workbook-quality.md`.\n\n---\n\n---\nname: csv-findings\ndescription: Produce clean findings CSV files that spreadsheet tools can open reliably.\n---\n\n# csv-findings\n\nUse this skill for required findings, exceptions, reconciliation, or signal CSV deliverables.\n\n## Output contract\n\n- Write CSV files to `{folderPath}/perch-output/`.\n- Use deterministic column order from the base prompt.\n- Return the CSV path in `outputFiles`.\n\n## How to build the CSV\n\nPrefer writing a small Python script to `/tmp/<workflow>-csv-findings.py` and running it with Bash when quoting, commas, newlines, or currency values could be tricky. Use the standard library `csv` module, create `{folderPath}/perch-output/`, and verify with `ls -l "{folderPath}/perch-output/"`.\n\n```python\nimport csv\nfrom pathlib import Path\n\nout_dir = Path(folder_path) / "perch-output"\nout_dir.mkdir(parents=True, exist_ok=True)\nwith (out_dir / "findings.csv").open("w", newline="", encoding="utf-8") as f:\n writer = csv.DictWriter(f, fieldnames=["id", "severity", "category", "title", "financial_exposure", "evidence"])\n writer.writeheader()\n writer.writerows(rows)\n```\n\n## Conventions\n\n- Preserve exact IDs, names, amounts, accounts, dates, and source filenames from the analyst or sandbox output.\n- Quote fields through the CSV writer; do not hand-escape rows.\n- Use blank cells for missing values rather than invented values.\n- If there are no findings, still write the header row.',
|
|
87187
87186
|
"allowedTools": [
|
|
87188
87187
|
"writeLocalFile",
|
|
87189
87188
|
"bash",
|
|
@@ -89181,7 +89180,7 @@ var init_managedWorkflowRegistry = __esm({
|
|
|
89181
89180
|
"name": "Payroll Publisher",
|
|
89182
89181
|
"description": "Publishes a payroll approval memo from deterministic run artifacts without recalculating payroll.",
|
|
89183
89182
|
"lane": "writer",
|
|
89184
|
-
"systemPrompt": "# Payroll Publisher\n\nYou publish an approval memo for a completed payroll run.\n\nUse only the deterministic payroll artifact and the analyst output. You may write a short `payroll_output/approval_cover_memo.md` if asked by the coordinator, but you must not alter gross pay, tax cells, deductions, provider import files, or source timesheets.\n\nIf the run is blocked, the memo must say provider import files are not safe to upload until the listed exceptions are fixed and the suite is rerun.\n\nReturn valid JSON matching `schemas/payroll-publisher-output.json
|
|
89183
|
+
"systemPrompt": "# Payroll Publisher\n\nYou publish an approval memo for a completed payroll run.\n\nUse only the deterministic payroll artifact and the analyst output. You may write a short `payroll_output/approval_cover_memo.md` if asked by the coordinator, but you must not alter gross pay, tax cells, deductions, provider import files, or source timesheets.\n\nIf the run is blocked, the memo must say provider import files are not safe to upload until the listed exceptions are fixed and the suite is rerun.\n\nReturn valid JSON matching `schemas/payroll-publisher-output.json`.\n\n---\n\n# Core Perch skill: documents\n\n\n# documents\n\nUse this skill when the user asks Perch to create, revise, review, redline, or deliver a document-shaped artifact.\n\n## Operating Rules\n\n- For long documents, outline the structure before writing the full body.\n- Keep the output as a real deliverable: DOCX, Markdown, Google Doc, or another explicitly requested document target.\n- Preserve source-grounded claims. Load `research`, `pdf`, or `workspace` when citations, page evidence, local files, or source packets drive the content.\n- For Google Docs, use a verified Google Docs shortcut when it can return proof, or hand off to `browser-operator` for live browser editing.\n- Do not claim a header, footer, comment, tracked edit, or page layout feature if the current surface cannot verify it.\n\n## Verification\n\nBefore delivery, check title, body, section order, missing placeholders, citation handoff, and saved file state. Use `references/verification.md` for the compact QA checklist.",
|
|
89185
89184
|
"allowedTools": [
|
|
89186
89185
|
"writeLocalFile",
|
|
89187
89186
|
"readLocalSourceFile",
|
|
@@ -89858,7 +89857,7 @@ var init_managedWorkflowRegistry = __esm({
|
|
|
89858
89857
|
"name": "Statement Publisher",
|
|
89859
89858
|
"description": "Writes the statement audit findings and reconciliation to the output folder.",
|
|
89860
89859
|
"lane": "writer",
|
|
89861
|
-
"systemPrompt": '# Statement Publisher\n\nYou receive the analyst\'s structured output. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `nav-reconciliation.csv`** \u2014 one row per finding from `sandboxArtifact.findings`:\n```\nid,severity,investor,lp_nav,admin_nav,gap,detail\nstmt-nav-mismatch-1,critical,Alpha Capital,200000,115000,85000,"LP ending $200k vs fund admin $115k"\n```\n\n**2. `statement-report.md`** \u2014 structured markdown:\n```markdown\n# LP Statement Audit Report \u2014 {folder name}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## NAV Reconciliation\n{For each finding: investor name, LP NAV, admin NAV, gap amount, source files}\n\n## Recommended Actions\n{Numbered list \u2014 e.g. "Reconcile Alpha Capital $85,000 gap with fund admin before LP distribution"}\n\n## Coverage\n- LP statement records: {metrics.lpStatementRecords}\n- Fund admin records: {metrics.fundAdminRecords}\n- Total findings: {metrics.findingsCount}\n```\n\nThe `folderPath` is in `priorOutput.folderPath`. Use it to build output paths.\n\n## Rules\n\n1. **Write files first, return paths.** The CSV is what compliance reviews.\n2. Investor names and NAV figures must be verbatim from findings \u2014 never paraphrase amounts.\n3. Never fabricate mismatches not in `sandboxArtifact`.\n4. If sandboxArtifact or analyst output is missing, write a report.md explaining what failed.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "reconciliation": "{folderPath}/perch-output/nav-reconciliation.csv",\n "report": "{folderPath}/perch-output/statement-report.md"\n },\n "findingsCount": 0,\n "topFinding": "string or null"\n}\n```\n\n---\n\n
|
|
89860
|
+
"systemPrompt": '# Statement Publisher\n\nYou receive the analyst\'s structured output. Your job is to write deliverable files to disk \u2014 not to summarize in prose.\n\n## What to write\n\nUsing `writeLocalFile`, write two files to `{folderPath}/perch-output/`:\n\n**1. `nav-reconciliation.csv`** \u2014 one row per finding from `sandboxArtifact.findings`:\n```\nid,severity,investor,lp_nav,admin_nav,gap,detail\nstmt-nav-mismatch-1,critical,Alpha Capital,200000,115000,85000,"LP ending $200k vs fund admin $115k"\n```\n\n**2. `statement-report.md`** \u2014 structured markdown:\n```markdown\n# LP Statement Audit Report \u2014 {folder name}\nGenerated: {ISO date}\n\n## Executive Summary\n{analyst executiveSummary}\n\n## Risk Assessment\n**Level:** {level} \u2014 {justification}\n\n## NAV Reconciliation\n{For each finding: investor name, LP NAV, admin NAV, gap amount, source files}\n\n## Recommended Actions\n{Numbered list \u2014 e.g. "Reconcile Alpha Capital $85,000 gap with fund admin before LP distribution"}\n\n## Coverage\n- LP statement records: {metrics.lpStatementRecords}\n- Fund admin records: {metrics.fundAdminRecords}\n- Total findings: {metrics.findingsCount}\n```\n\nThe `folderPath` is in `priorOutput.folderPath`. Use it to build output paths.\n\n## Rules\n\n1. **Write files first, return paths.** The CSV is what compliance reviews.\n2. Investor names and NAV figures must be verbatim from findings \u2014 never paraphrase amounts.\n3. Never fabricate mismatches not in `sandboxArtifact`.\n4. If sandboxArtifact or analyst output is missing, write a report.md explaining what failed.\n\n## Producing Office Files\n\nThe markdown and CSV instructions above still apply. When an Excel workbook is requested or useful for review, produce it as an additional artifact:\n\n1. Use `writeLocalFile` to write a Python script under `/tmp/`.\n2. Run the script with Bash (`python3 /tmp/<script>.py`) using `bash` or `runBashTerminalCommand`.\n3. Save outputs under `{folderPath}/perch-output/`.\n4. Verify the files exist with `ls -l "{folderPath}/perch-output/"`.\n5. Return the verified path in `outputFiles`.\n\nIf the Python Office library is unavailable, fall back to a CSV artifact and return that path clearly.\n\n## Output Schema\n\n```json\n{\n "status": "completed|partial|failed",\n "outputFiles": {\n "reconciliation": "{folderPath}/perch-output/nav-reconciliation.csv",\n "report": "{folderPath}/perch-output/statement-report.md"\n },\n "findingsCount": 0,\n "topFinding": "string or null"\n}\n```\n\n---\n\n# Core Perch skill: spreadsheets\n\n\n# spreadsheets\n\nUse this skill when the user asks for a spreadsheet artifact, spreadsheet inspection, import-ready CSV, formulas, reconciliation tabs, exception tabs, or workbook-quality output.\n\n## Operating Rules\n\n- Profile incoming sheets before changing them: row counts, columns, types, key IDs, totals, and empty fields.\n- Preserve identifiers as text when they are invoice numbers, account numbers, vendor IDs, employee IDs, tickers, or other non-math values.\n- Put source values on input tabs and formulas on analysis tabs when producing XLSX workbooks.\n- Add checks for totals, row counts, formulas, and exception counts when the workbook drives a decision.\n- Use deterministic code or workbook inspection for fragile calculations; do not hand-wave formula behavior.\n\n## Verification\n\nBefore delivery, verify that the file exists, formulas are present where expected, totals reconcile, and CSV exports keep exact values. See `references/workbook-quality.md`.\n\n---\n\n---\nname: csv-findings\ndescription: Produce clean findings CSV files that spreadsheet tools can open reliably.\n---\n\n# csv-findings\n\nUse this skill for required findings, exceptions, reconciliation, or signal CSV deliverables.\n\n## Output contract\n\n- Write CSV files to `{folderPath}/perch-output/`.\n- Use deterministic column order from the base prompt.\n- Return the CSV path in `outputFiles`.\n\n## How to build the CSV\n\nPrefer writing a small Python script to `/tmp/<workflow>-csv-findings.py` and running it with Bash when quoting, commas, newlines, or currency values could be tricky. Use the standard library `csv` module, create `{folderPath}/perch-output/`, and verify with `ls -l "{folderPath}/perch-output/"`.\n\n```python\nimport csv\nfrom pathlib import Path\n\nout_dir = Path(folder_path) / "perch-output"\nout_dir.mkdir(parents=True, exist_ok=True)\nwith (out_dir / "findings.csv").open("w", newline="", encoding="utf-8") as f:\n writer = csv.DictWriter(f, fieldnames=["id", "severity", "category", "title", "financial_exposure", "evidence"])\n writer.writeheader()\n writer.writerows(rows)\n```\n\n## Conventions\n\n- Preserve exact IDs, names, amounts, accounts, dates, and source filenames from the analyst or sandbox output.\n- Quote fields through the CSV writer; do not hand-escape rows.\n- Use blank cells for missing values rather than invented values.\n- If there are no findings, still write the header row.',
|
|
89862
89861
|
"allowedTools": [
|
|
89863
89862
|
"writeLocalFile",
|
|
89864
89863
|
"bash",
|
|
@@ -92161,6 +92160,607 @@ Final message: concise for findings and receipts, usually 10 lines or fewer; con
|
|
|
92161
92160
|
}
|
|
92162
92161
|
});
|
|
92163
92162
|
|
|
92163
|
+
// generated/agentSkillRegistry.ts
|
|
92164
|
+
function getAgentSkillManifest(id) {
|
|
92165
|
+
return AGENT_SKILL_INDEX.get(id) ?? null;
|
|
92166
|
+
}
|
|
92167
|
+
function listAgentSkillMetadataRows() {
|
|
92168
|
+
return AGENT_SKILL_REGISTRY.map((skill) => ({
|
|
92169
|
+
id: skill.id,
|
|
92170
|
+
name: skill.name,
|
|
92171
|
+
description: skill.description,
|
|
92172
|
+
surface: skill.surface,
|
|
92173
|
+
triggerHints: skill.triggerHints.slice()
|
|
92174
|
+
}));
|
|
92175
|
+
}
|
|
92176
|
+
var AGENT_SKILL_REGISTRY, AGENT_SKILL_INDEX;
|
|
92177
|
+
var init_agentSkillRegistry = __esm({
|
|
92178
|
+
"generated/agentSkillRegistry.ts"() {
|
|
92179
|
+
"use strict";
|
|
92180
|
+
AGENT_SKILL_REGISTRY = [
|
|
92181
|
+
{
|
|
92182
|
+
"id": "browser-operator",
|
|
92183
|
+
"name": "browser-operator",
|
|
92184
|
+
"description": "Operate Perch's logged-in browser surface using visual state, semantic DOM targets, and coordinate actions when available.",
|
|
92185
|
+
"path": "features/perchTerminal/agentPlatform/skills/browser-operator/SKILL.md",
|
|
92186
|
+
"body": "\n# browser-operator\n\nUse this skill when Perch must operate a live browser page, especially logged-in apps like Google Docs, Gmail, Calendar, SaaS portals, admin consoles, and forms.\n\n## Operating Loop\n\n1. Observe the current page before acting.\n2. For a short multi-step job, use `browser_execute_task` with `goal`, `requiredValues`, `successCriteria`, and a bounded `steps` list.\n3. For a one-off recovery action, decide whether the next action is semantic or visual.\n4. Take one action.\n5. Observe again and verify the result before continuing.\n6. Stop with a clear blocker when the required action surface is missing.\n\n## Tool Choice\n\n- Use semantic tools for normal web controls: buttons, links, menus, named fields, and visible labels.\n- Prefer `browser_execute_task` when the sequence includes fill \u2192 verify \u2192 submit/save/send. Put the exact recipient, subject, body excerpt, title, date/time, or other must-land values in `requiredValues`.\n- Use `browser_visual_click` or `browser_focus_type` for canvas, iframe, whiteboard, document-body, drag/drop, or visually obvious targets that are not exposed as DOM elements.\n- If coordinate tools are unavailable and the target is only visually reachable, do not loop semantic clicks. Report the missing visual-action capability.\n- For text entry, first focus the target, then type into the focused surface. Do not assume a successful keypress means the text landed.\n\n## Google Docs Rules\n\n- Do not inspect, open, or change the Docs mode dropdown during normal writing. New Docs should already start in Editing mode.\n- If the visible toolbar is already read-only, `Viewing mode`, or `Suggesting mode`, stop and report a permission/mode blocker instead of trying to switch modes yourself.\n- Never click the eye/pencil/mode control or hidden zero-size `Viewing mode` entries. Treat those as fragile controls, not recovery targets.\n- Collapse Document tabs / outline panels before typing if they cover the page.\n- Do not rely on DOM text readback for the document body. Google Docs Kix can show text visually while DOM snapshots stay blank.\n- Body writing should use `browser_focus_type`: visual click into the paper area plus focused typing/key events.\n- Verify by URL, title, save status, and screenshot/visual proof. Treat DOM body text as optional evidence only.\n- Never keep retrying `browser_click` with an empty target. If the paper body is only reachable by coordinate, use coordinate click or stop.\n\n## Completion Proof\n\nReturn success only when there is visible proof, such as:\n\n- a saved/created/sent status,\n- a stable URL,\n- a title or body marker visible in the screenshot,\n- a sent toast or delivery receipt.\n\nIf proof is missing, continue with the next valid recovery path or report the blocker. Do not claim completion from intent alone.",
|
|
92187
|
+
"surface": {
|
|
92188
|
+
"gui": "supported",
|
|
92189
|
+
"cli": "limited"
|
|
92190
|
+
},
|
|
92191
|
+
"triggerHints": [
|
|
92192
|
+
"browser",
|
|
92193
|
+
"web app",
|
|
92194
|
+
"logged-in app",
|
|
92195
|
+
"browser google docs",
|
|
92196
|
+
"gmail browser",
|
|
92197
|
+
"calendar browser",
|
|
92198
|
+
"saas portal",
|
|
92199
|
+
"browser form"
|
|
92200
|
+
],
|
|
92201
|
+
"companionSkills": [
|
|
92202
|
+
"documents",
|
|
92203
|
+
"research",
|
|
92204
|
+
"workspace"
|
|
92205
|
+
],
|
|
92206
|
+
"preferredTools": [
|
|
92207
|
+
"browser_execute_task",
|
|
92208
|
+
"browser_observe",
|
|
92209
|
+
"browser_click",
|
|
92210
|
+
"browser_type",
|
|
92211
|
+
"browser_visual_click",
|
|
92212
|
+
"browser_focus_type",
|
|
92213
|
+
"browser_press_key",
|
|
92214
|
+
"browser_read",
|
|
92215
|
+
"browser_wait",
|
|
92216
|
+
"browser_navigate"
|
|
92217
|
+
]
|
|
92218
|
+
},
|
|
92219
|
+
{
|
|
92220
|
+
"id": "data-quality",
|
|
92221
|
+
"name": "data-quality",
|
|
92222
|
+
"description": "Profile messy data, find anomalies, reconcile systems, explain exceptions, score risk, and produce audit-ready evidence through deterministic math before narrative.",
|
|
92223
|
+
"path": "features/perchTerminal/agentPlatform/skills/data-quality/SKILL.md",
|
|
92224
|
+
"body": "\n# data-quality\n\nUse this skill when the user asks for anomalies, duplicates, reconciliations, risk scoring, exception analysis, or audit-ready data evidence.\n\n## Operating Rules\n\n- Run deterministic math before narrative whenever source tables or files are available.\n- Profile schemas, row counts, nulls, key fields, duplicate keys, totals, and join coverage.\n- Preserve exact identifiers, dates, amounts, source filenames, and exception IDs.\n- Explain each exception with evidence and uncertainty, not only a risk label.\n- Use `spreadsheets` for workbook deliverables and `diagrams` for relationship or network outputs.\n\n## Verification\n\nTie totals, duplicate counts, exception rows, and risk outputs back to deterministic evidence. See `references/reconciliation.md`.",
|
|
92225
|
+
"surface": {
|
|
92226
|
+
"gui": "supported",
|
|
92227
|
+
"cli": "supported"
|
|
92228
|
+
},
|
|
92229
|
+
"triggerHints": [
|
|
92230
|
+
"data quality",
|
|
92231
|
+
"anomaly",
|
|
92232
|
+
"reconciliation",
|
|
92233
|
+
"duplicate payment",
|
|
92234
|
+
"duplicate invoice",
|
|
92235
|
+
"tie out",
|
|
92236
|
+
"row totals",
|
|
92237
|
+
"audit exceptions",
|
|
92238
|
+
"vendor risk",
|
|
92239
|
+
"outlier",
|
|
92240
|
+
"missing receipt",
|
|
92241
|
+
"cost anomaly"
|
|
92242
|
+
],
|
|
92243
|
+
"companionSkills": [
|
|
92244
|
+
"spreadsheets",
|
|
92245
|
+
"workspace",
|
|
92246
|
+
"pdf",
|
|
92247
|
+
"diagrams"
|
|
92248
|
+
],
|
|
92249
|
+
"preferredTools": [
|
|
92250
|
+
"run_sandbox_code",
|
|
92251
|
+
"runSandboxAnalysis",
|
|
92252
|
+
"prepareSandboxInputs",
|
|
92253
|
+
"generateAPAuditPacket",
|
|
92254
|
+
"render_ap_control_graph",
|
|
92255
|
+
"readLocalFile",
|
|
92256
|
+
"writeLocalFile"
|
|
92257
|
+
]
|
|
92258
|
+
},
|
|
92259
|
+
{
|
|
92260
|
+
"id": "diagrams",
|
|
92261
|
+
"name": "diagrams",
|
|
92262
|
+
"description": "Create, edit, and verify diagrams, graphs, workflows, org charts, entity networks, control graphs, architecture maps, and evidence-backed visual structures.",
|
|
92263
|
+
"path": "features/perchTerminal/agentPlatform/skills/diagrams/SKILL.md",
|
|
92264
|
+
"body": "\n# diagrams\n\nUse this skill when the user asks for a diagram, graph, workflow, architecture map, network, org chart, or visual relationship model.\n\n## Operating Rules\n\n- Choose diagram format by use: Mermaid for simple structural diagrams, richer rendered artifacts for shareable or visually complex output.\n- Keep charts and diagrams distinct. Charts quantify data; diagrams explain structure, flow, responsibility, or relationships.\n- Tie graph nodes and edges to evidence when the diagram represents real entities, controls, risks, or findings.\n- Use `data-quality` for anomaly and reconciliation networks, and `presentations` or `documents` when the diagram needs to land in a deck or memo.\n\n## Verification\n\nRender or inspect complex diagrams before delivery. Confirm labels are readable, layout is not tangled, and evidence-backed nodes are traceable. See `references/diagram-quality.md`.",
|
|
92265
|
+
"surface": {
|
|
92266
|
+
"gui": "supported",
|
|
92267
|
+
"cli": "supported"
|
|
92268
|
+
},
|
|
92269
|
+
"triggerHints": [
|
|
92270
|
+
"diagram",
|
|
92271
|
+
"mermaid",
|
|
92272
|
+
"drawio",
|
|
92273
|
+
"workflow graph",
|
|
92274
|
+
"org chart",
|
|
92275
|
+
"entity network",
|
|
92276
|
+
"control graph",
|
|
92277
|
+
"architecture map",
|
|
92278
|
+
"vendor-risk graph",
|
|
92279
|
+
"node edge"
|
|
92280
|
+
],
|
|
92281
|
+
"companionSkills": [
|
|
92282
|
+
"data-quality",
|
|
92283
|
+
"documents",
|
|
92284
|
+
"presentations",
|
|
92285
|
+
"workspace"
|
|
92286
|
+
],
|
|
92287
|
+
"preferredTools": [
|
|
92288
|
+
"render_ap_control_graph",
|
|
92289
|
+
"createTextArtifact",
|
|
92290
|
+
"writeLocalFile",
|
|
92291
|
+
"run_sandbox_code",
|
|
92292
|
+
"visionInspect"
|
|
92293
|
+
]
|
|
92294
|
+
},
|
|
92295
|
+
{
|
|
92296
|
+
"id": "documents",
|
|
92297
|
+
"name": "documents",
|
|
92298
|
+
"description": "Create, edit, verify, and deliver professional document artifacts such as DOCX, Google Docs, memos, letters, reports, redlines, and formal written deliverables.",
|
|
92299
|
+
"path": "features/perchTerminal/agentPlatform/skills/documents/SKILL.md",
|
|
92300
|
+
"body": "\n# documents\n\nUse this skill when the user asks Perch to create, revise, review, redline, or deliver a document-shaped artifact.\n\n## Operating Rules\n\n- For long documents, outline the structure before writing the full body.\n- Keep the output as a real deliverable: DOCX, Markdown, Google Doc, or another explicitly requested document target.\n- Preserve source-grounded claims. Load `research`, `pdf`, or `workspace` when citations, page evidence, local files, or source packets drive the content.\n- For Google Docs, use a verified Google Docs shortcut when it can return proof, or hand off to `browser-operator` for live browser editing.\n- Do not claim a header, footer, comment, tracked edit, or page layout feature if the current surface cannot verify it.\n\n## Verification\n\nBefore delivery, check title, body, section order, missing placeholders, citation handoff, and saved file state. Use `references/verification.md` for the compact QA checklist.",
|
|
92301
|
+
"surface": {
|
|
92302
|
+
"gui": "supported",
|
|
92303
|
+
"cli": "supported"
|
|
92304
|
+
},
|
|
92305
|
+
"triggerHints": [
|
|
92306
|
+
"document",
|
|
92307
|
+
"docx",
|
|
92308
|
+
"word file",
|
|
92309
|
+
"google doc",
|
|
92310
|
+
"memo",
|
|
92311
|
+
"letter",
|
|
92312
|
+
"report",
|
|
92313
|
+
"redline",
|
|
92314
|
+
"tracked changes",
|
|
92315
|
+
"policy",
|
|
92316
|
+
"formal artifact"
|
|
92317
|
+
],
|
|
92318
|
+
"companionSkills": [
|
|
92319
|
+
"research",
|
|
92320
|
+
"pdf",
|
|
92321
|
+
"workspace",
|
|
92322
|
+
"browser-operator"
|
|
92323
|
+
],
|
|
92324
|
+
"preferredTools": [
|
|
92325
|
+
"createDocumentArtifact",
|
|
92326
|
+
"writeLocalFile",
|
|
92327
|
+
"google_docs_create_verified",
|
|
92328
|
+
"google_docs_create",
|
|
92329
|
+
"browser_execute_task",
|
|
92330
|
+
"readLocalFile",
|
|
92331
|
+
"visionInspect"
|
|
92332
|
+
]
|
|
92333
|
+
},
|
|
92334
|
+
{
|
|
92335
|
+
"id": "pdf",
|
|
92336
|
+
"name": "pdf",
|
|
92337
|
+
"description": "Extract, summarize, cite, split, merge, create, inspect, and verify PDF content, including text PDFs, scanned PDFs, tables, forms, page citations, and generated reports.",
|
|
92338
|
+
"path": "features/perchTerminal/agentPlatform/skills/pdf/SKILL.md",
|
|
92339
|
+
"body": "\n# pdf\n\nUse this skill when PDF content is the source, destination, or verification target.\n\n## Operating Rules\n\n- Preserve page awareness. Cite exact pages when answering from a PDF.\n- Treat PDF-to-Markdown and OCR as intermediate views, not final truth.\n- Use table-aware extraction or deterministic code when numbers, rows, or column alignment matter.\n- For scanned PDFs, use visual or OCR fallback and report uncertainty when text is unreadable.\n- Do not invent citations, fields, signatures, or form values.\n\n## Verification\n\nCheck that cited pages support the answer, table values are not flattened incorrectly, and generated PDFs render as expected. See `references/page-citations.md`.",
|
|
92340
|
+
"surface": {
|
|
92341
|
+
"gui": "supported",
|
|
92342
|
+
"cli": "supported"
|
|
92343
|
+
},
|
|
92344
|
+
"triggerHints": [
|
|
92345
|
+
"pdf",
|
|
92346
|
+
"annual report pdf",
|
|
92347
|
+
"scanned pdf",
|
|
92348
|
+
"page citation",
|
|
92349
|
+
"pdf table",
|
|
92350
|
+
"split pdf",
|
|
92351
|
+
"merge pdf",
|
|
92352
|
+
"form pdf",
|
|
92353
|
+
"ocr",
|
|
92354
|
+
"pdf report"
|
|
92355
|
+
],
|
|
92356
|
+
"companionSkills": [
|
|
92357
|
+
"research",
|
|
92358
|
+
"documents",
|
|
92359
|
+
"workspace",
|
|
92360
|
+
"data-quality"
|
|
92361
|
+
],
|
|
92362
|
+
"preferredTools": [
|
|
92363
|
+
"extractDocument",
|
|
92364
|
+
"extractDocumentSection",
|
|
92365
|
+
"visionInspect",
|
|
92366
|
+
"readLocalFile",
|
|
92367
|
+
"run_sandbox_code",
|
|
92368
|
+
"webFetch"
|
|
92369
|
+
]
|
|
92370
|
+
},
|
|
92371
|
+
{
|
|
92372
|
+
"id": "presentations",
|
|
92373
|
+
"name": "presentations",
|
|
92374
|
+
"description": "Build executive decks, board decks, sales decks, research summaries, and visual narratives as PPTX or shareable slide artifacts with verified layout and source-backed content.",
|
|
92375
|
+
"path": "features/perchTerminal/agentPlatform/skills/presentations/SKILL.md",
|
|
92376
|
+
"body": "\n# presentations\n\nUse this skill when the user asks for slides, a deck, a board packet, a pitch, or a visual narrative.\n\n## Operating Rules\n\n- Start with audience, decision, and slide outline before building a long deck.\n- Each slide should carry one takeaway; supporting charts, tables, and bullets must serve that takeaway.\n- Source every important number or claim from provided evidence, workspace files, research, or companion skills.\n- Use `spreadsheets` for chart data, `diagrams` for networks and workflows, and `pdf` when source packets are page-cited.\n- Prefer real deck files when requested. HTML slide experiences are acceptable only when design iteration or sharing calls for them.\n\n## Verification\n\nCheck slide count, readable text, non-overflowing layout, chart/image rendering, and file existence before delivery. See `references/deck-quality.md`.",
|
|
92377
|
+
"surface": {
|
|
92378
|
+
"gui": "supported",
|
|
92379
|
+
"cli": "supported"
|
|
92380
|
+
},
|
|
92381
|
+
"triggerHints": [
|
|
92382
|
+
"deck",
|
|
92383
|
+
"pptx",
|
|
92384
|
+
"powerpoint",
|
|
92385
|
+
"board deck",
|
|
92386
|
+
"slide deck",
|
|
92387
|
+
"presentation",
|
|
92388
|
+
"executive deck",
|
|
92389
|
+
"pitch deck",
|
|
92390
|
+
"sales deck",
|
|
92391
|
+
"speaker notes",
|
|
92392
|
+
"chart slide"
|
|
92393
|
+
],
|
|
92394
|
+
"companionSkills": [
|
|
92395
|
+
"documents",
|
|
92396
|
+
"spreadsheets",
|
|
92397
|
+
"research",
|
|
92398
|
+
"diagrams",
|
|
92399
|
+
"pdf",
|
|
92400
|
+
"workspace"
|
|
92401
|
+
],
|
|
92402
|
+
"preferredTools": [
|
|
92403
|
+
"writeLocalFile",
|
|
92404
|
+
"run_sandbox_code",
|
|
92405
|
+
"createDocumentArtifact",
|
|
92406
|
+
"visionInspect",
|
|
92407
|
+
"readLocalFile"
|
|
92408
|
+
]
|
|
92409
|
+
},
|
|
92410
|
+
{
|
|
92411
|
+
"id": "research",
|
|
92412
|
+
"name": "research",
|
|
92413
|
+
"description": "Gather, compare, rank, and cite evidence from public web sources, scholarly sources, workspace files, source packets, Qdrant knowledge, and attached local folders.",
|
|
92414
|
+
"path": "features/perchTerminal/agentPlatform/skills/research/SKILL.md",
|
|
92415
|
+
"body": "\n# research\n\nUse this skill when the user asks Perch to gather, compare, verify, or cite evidence.\n\n## Operating Rules\n\n- Choose the source lane intentionally: current public questions use web; attached folders use workspace or local sources; internal product questions use repo/workspace evidence; stored examples use knowledge.\n- Do not use knowledge retrieval as a catch-all when a domain or workspace tool is more direct.\n- Rank sources by authority, recency, relevance, and proximity to the claim.\n- Surface contradictions instead of averaging them away.\n- Keep citations concise and visibly tied to titles, URLs, files, pages, or evidence IDs.\n\n## Verification\n\nCheck freshness requirements, cite the actual sources used, and label uncertainty when sources are missing or disagree. See `references/source-quality.md`.",
|
|
92416
|
+
"surface": {
|
|
92417
|
+
"gui": "supported",
|
|
92418
|
+
"cli": "supported"
|
|
92419
|
+
},
|
|
92420
|
+
"triggerHints": [
|
|
92421
|
+
"research",
|
|
92422
|
+
"web research",
|
|
92423
|
+
"credible sources",
|
|
92424
|
+
"current source",
|
|
92425
|
+
"citation",
|
|
92426
|
+
"source comparison",
|
|
92427
|
+
"filing",
|
|
92428
|
+
"scholarly source",
|
|
92429
|
+
"public web",
|
|
92430
|
+
"fact check",
|
|
92431
|
+
"latest"
|
|
92432
|
+
],
|
|
92433
|
+
"companionSkills": [
|
|
92434
|
+
"pdf",
|
|
92435
|
+
"documents",
|
|
92436
|
+
"workspace",
|
|
92437
|
+
"data-quality"
|
|
92438
|
+
],
|
|
92439
|
+
"preferredTools": [
|
|
92440
|
+
"webSearch",
|
|
92441
|
+
"webFetch",
|
|
92442
|
+
"scholarSearch",
|
|
92443
|
+
"searchKnowledge",
|
|
92444
|
+
"searchWorkspaceSources",
|
|
92445
|
+
"readLocalSourceFile",
|
|
92446
|
+
"listLocalSources"
|
|
92447
|
+
]
|
|
92448
|
+
},
|
|
92449
|
+
{
|
|
92450
|
+
"id": "skill-creator",
|
|
92451
|
+
"name": "skill-creator",
|
|
92452
|
+
"description": "Create, validate, package, and test Perch skills with frontmatter checks, trigger collision detection, reference validation, surface metadata, and acceptance tasks.",
|
|
92453
|
+
"path": "features/perchTerminal/agentPlatform/skills/skill-creator/SKILL.md",
|
|
92454
|
+
"body": "\n# skill-creator\n\nUse this skill when creating, updating, validating, or evaluating Perch skills.\n\n## Operating Rules\n\n- Keep each skill as one reusable workflow unit with `SKILL.md`, optional `references/`, optional `scripts/`, and optional `assets/`.\n- Frontmatter must include `name`, `description`, and Perch metadata for GUI and CLI surface support.\n- Trigger hints should be precise enough to activate the skill without colliding with unrelated skills.\n- Put detailed reusable rules in reference files and fragile deterministic checks in scripts.\n- Add at least one acceptance task for each supported surface when the skill is productized.\n\n## Verification\n\nRun skill codegen and registry tests after edits. Use `references/validation-checklist.md` before declaring a skill ready.",
|
|
92455
|
+
"surface": {
|
|
92456
|
+
"gui": "supported",
|
|
92457
|
+
"cli": "supported"
|
|
92458
|
+
},
|
|
92459
|
+
"triggerHints": [
|
|
92460
|
+
"skill creator",
|
|
92461
|
+
"create skill",
|
|
92462
|
+
"skill.md",
|
|
92463
|
+
"agent skill",
|
|
92464
|
+
"skill validation",
|
|
92465
|
+
"trigger collision",
|
|
92466
|
+
"skill test",
|
|
92467
|
+
"skill authoring",
|
|
92468
|
+
"perch skill"
|
|
92469
|
+
],
|
|
92470
|
+
"companionSkills": [
|
|
92471
|
+
"workspace",
|
|
92472
|
+
"data-quality"
|
|
92473
|
+
],
|
|
92474
|
+
"preferredTools": [
|
|
92475
|
+
"glob",
|
|
92476
|
+
"grep",
|
|
92477
|
+
"readLocalFile",
|
|
92478
|
+
"writeLocalFile",
|
|
92479
|
+
"bash"
|
|
92480
|
+
]
|
|
92481
|
+
},
|
|
92482
|
+
{
|
|
92483
|
+
"id": "spreadsheets",
|
|
92484
|
+
"name": "spreadsheets",
|
|
92485
|
+
"description": "Create, inspect, clean, calculate, format, and verify spreadsheet artifacts such as XLSX, CSV, TSV, Google Sheets, formulas, pivots, charts, and reconciliation workbooks.",
|
|
92486
|
+
"path": "features/perchTerminal/agentPlatform/skills/spreadsheets/SKILL.md",
|
|
92487
|
+
"body": "\n# spreadsheets\n\nUse this skill when the user asks for a spreadsheet artifact, spreadsheet inspection, import-ready CSV, formulas, reconciliation tabs, exception tabs, or workbook-quality output.\n\n## Operating Rules\n\n- Profile incoming sheets before changing them: row counts, columns, types, key IDs, totals, and empty fields.\n- Preserve identifiers as text when they are invoice numbers, account numbers, vendor IDs, employee IDs, tickers, or other non-math values.\n- Put source values on input tabs and formulas on analysis tabs when producing XLSX workbooks.\n- Add checks for totals, row counts, formulas, and exception counts when the workbook drives a decision.\n- Use deterministic code or workbook inspection for fragile calculations; do not hand-wave formula behavior.\n\n## Verification\n\nBefore delivery, verify that the file exists, formulas are present where expected, totals reconcile, and CSV exports keep exact values. See `references/workbook-quality.md`.",
|
|
92488
|
+
"surface": {
|
|
92489
|
+
"gui": "supported",
|
|
92490
|
+
"cli": "supported"
|
|
92491
|
+
},
|
|
92492
|
+
"triggerHints": [
|
|
92493
|
+
"spreadsheet",
|
|
92494
|
+
"xlsx",
|
|
92495
|
+
"excel workbook",
|
|
92496
|
+
"csv",
|
|
92497
|
+
"tsv",
|
|
92498
|
+
"google sheet",
|
|
92499
|
+
"formula",
|
|
92500
|
+
"pivot",
|
|
92501
|
+
"reconciliation tab",
|
|
92502
|
+
"exception tab",
|
|
92503
|
+
"import template",
|
|
92504
|
+
"row count",
|
|
92505
|
+
"workbook check"
|
|
92506
|
+
],
|
|
92507
|
+
"companionSkills": [
|
|
92508
|
+
"data-quality",
|
|
92509
|
+
"workspace",
|
|
92510
|
+
"pdf",
|
|
92511
|
+
"research"
|
|
92512
|
+
],
|
|
92513
|
+
"preferredTools": [
|
|
92514
|
+
"inspectWorkbookSheets",
|
|
92515
|
+
"google_sheets_create",
|
|
92516
|
+
"google_sheets_append_rows",
|
|
92517
|
+
"writeLocalFile",
|
|
92518
|
+
"run_sandbox_code",
|
|
92519
|
+
"bash",
|
|
92520
|
+
"readLocalFile"
|
|
92521
|
+
]
|
|
92522
|
+
},
|
|
92523
|
+
{
|
|
92524
|
+
"id": "workspace",
|
|
92525
|
+
"name": "workspace",
|
|
92526
|
+
"description": "Navigate, inspect, search, summarize, and safely edit local workspaces, attached folders, source inventories, project files, and codebases with exact file-grounded evidence.",
|
|
92527
|
+
"path": "features/perchTerminal/agentPlatform/skills/workspace/SKILL.md",
|
|
92528
|
+
"body": "\n# workspace\n\nUse this skill when the task requires local files, attached folders, repo search, safe edits, or source inventory.\n\n## Operating Rules\n\n- Start with inventory or targeted search before reading many files.\n- Cite exact files when answering codebase or workspace questions.\n- Distinguish direct filesystem reads, indexed local source retrieval, Supabase source packets, and Qdrant knowledge.\n- Do not say Perch cannot access a file path when the local runtime and permissions make it accessible.\n- For edits, keep changes scoped and preserve unrelated user work.\n\n## Verification\n\nCheck file existence, paths, and write results before reporting completion. Use `references/source-boundaries.md` to keep source lanes clear.",
|
|
92529
|
+
"surface": {
|
|
92530
|
+
"gui": "supported",
|
|
92531
|
+
"cli": "supported"
|
|
92532
|
+
},
|
|
92533
|
+
"triggerHints": [
|
|
92534
|
+
"repo",
|
|
92535
|
+
"codebase",
|
|
92536
|
+
"local folder",
|
|
92537
|
+
"workspace",
|
|
92538
|
+
"find file",
|
|
92539
|
+
"inspect folder",
|
|
92540
|
+
"search files",
|
|
92541
|
+
"edit file",
|
|
92542
|
+
"source inventory",
|
|
92543
|
+
"project files"
|
|
92544
|
+
],
|
|
92545
|
+
"companionSkills": [
|
|
92546
|
+
"research",
|
|
92547
|
+
"pdf",
|
|
92548
|
+
"data-quality",
|
|
92549
|
+
"skill-creator"
|
|
92550
|
+
],
|
|
92551
|
+
"preferredTools": [
|
|
92552
|
+
"glob",
|
|
92553
|
+
"grep",
|
|
92554
|
+
"readLocalFile",
|
|
92555
|
+
"writeLocalFile",
|
|
92556
|
+
"statPath",
|
|
92557
|
+
"listLocalSources",
|
|
92558
|
+
"readLocalSourceFile",
|
|
92559
|
+
"bash"
|
|
92560
|
+
]
|
|
92561
|
+
}
|
|
92562
|
+
];
|
|
92563
|
+
AGENT_SKILL_INDEX = /* @__PURE__ */ new Map();
|
|
92564
|
+
for (const skill of AGENT_SKILL_REGISTRY) {
|
|
92565
|
+
if (AGENT_SKILL_INDEX.has(skill.id)) {
|
|
92566
|
+
throw new Error(`generated registry duplicate skill id: ${skill.id}`);
|
|
92567
|
+
}
|
|
92568
|
+
AGENT_SKILL_INDEX.set(skill.id, skill);
|
|
92569
|
+
}
|
|
92570
|
+
}
|
|
92571
|
+
});
|
|
92572
|
+
|
|
92573
|
+
// features/perchTerminal/agentPlatform/skills/skillSelector.ts
|
|
92574
|
+
function normalizeText(input) {
|
|
92575
|
+
return input.toLowerCase().replace(/\s+/g, " ").trim();
|
|
92576
|
+
}
|
|
92577
|
+
function escapeRegExp2(input) {
|
|
92578
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
92579
|
+
}
|
|
92580
|
+
function triggerMatches(text, trigger) {
|
|
92581
|
+
const normalized = normalizeText(trigger);
|
|
92582
|
+
if (!normalized) return false;
|
|
92583
|
+
return new RegExp(`(^|[^a-z0-9])${escapeRegExp2(normalized)}([^a-z0-9]|$)`, "i").test(text);
|
|
92584
|
+
}
|
|
92585
|
+
function skillMatches(skill, text) {
|
|
92586
|
+
if (skill.triggerHints.some((trigger) => triggerMatches(text, trigger))) {
|
|
92587
|
+
return true;
|
|
92588
|
+
}
|
|
92589
|
+
return (INTENT_PATTERNS[skill.id] ?? []).some(
|
|
92590
|
+
(pattern) => pattern.test(text)
|
|
92591
|
+
);
|
|
92592
|
+
}
|
|
92593
|
+
function isMarketDeskSignalTask(text, availableToolNames) {
|
|
92594
|
+
const hasMarketDeskTool = [...MARKET_DESK_TOOL_NAMES].some(
|
|
92595
|
+
(toolName) => availableToolNames.has(toolName)
|
|
92596
|
+
);
|
|
92597
|
+
return hasMarketDeskTool && /\b(market\s+desk|signal|strategy|backtest|track\s+record)\b/i.test(text) && /\b[A-Z]{1,5}\b/.test(text);
|
|
92598
|
+
}
|
|
92599
|
+
function selectionText(input) {
|
|
92600
|
+
return [
|
|
92601
|
+
input.userMessage,
|
|
92602
|
+
input.currentMode ?? "",
|
|
92603
|
+
input.personaId ?? "",
|
|
92604
|
+
input.selectedFolder ?? "",
|
|
92605
|
+
...input.selectedFiles ?? [],
|
|
92606
|
+
input.sourceSummary ?? ""
|
|
92607
|
+
].filter(Boolean).join("\n");
|
|
92608
|
+
}
|
|
92609
|
+
function canUseSkillOnSurface(skill, input, availableToolNames) {
|
|
92610
|
+
if (skill.surface[input.surface] === "unsupported") {
|
|
92611
|
+
return `${input.surface.toUpperCase()} surface is unsupported`;
|
|
92612
|
+
}
|
|
92613
|
+
if (skill.id === "browser-operator" && ![...availableToolNames].some((toolName) => BROWSER_TOOL_NAMES.has(toolName))) {
|
|
92614
|
+
return "browser operator tools are not available this turn";
|
|
92615
|
+
}
|
|
92616
|
+
return null;
|
|
92617
|
+
}
|
|
92618
|
+
function priorityIndex(skillId) {
|
|
92619
|
+
const index = CORE_PRIORITY.indexOf(skillId);
|
|
92620
|
+
return index === -1 ? CORE_PRIORITY.length : index;
|
|
92621
|
+
}
|
|
92622
|
+
function sortSkillIds(ids) {
|
|
92623
|
+
return [...ids].sort(
|
|
92624
|
+
(a, b2) => priorityIndex(a) - priorityIndex(b2) || a.localeCompare(b2)
|
|
92625
|
+
);
|
|
92626
|
+
}
|
|
92627
|
+
function selectAgentSkills(input) {
|
|
92628
|
+
const maxSelected = Math.max(
|
|
92629
|
+
0,
|
|
92630
|
+
input.maxSelectedSkills ?? DEFAULT_MAX_SELECTED_SKILLS
|
|
92631
|
+
);
|
|
92632
|
+
const availableToolNames = new Set(input.availableToolNames ?? []);
|
|
92633
|
+
const text = selectionText(input);
|
|
92634
|
+
const normalizedText = normalizeText(text);
|
|
92635
|
+
const byId = new Map(AGENT_SKILL_REGISTRY.map((skill) => [skill.id, skill]));
|
|
92636
|
+
const metadataRows = AGENT_SKILL_REGISTRY.map((skill) => ({
|
|
92637
|
+
id: skill.id,
|
|
92638
|
+
name: skill.name,
|
|
92639
|
+
description: skill.description
|
|
92640
|
+
}));
|
|
92641
|
+
const omitted = [];
|
|
92642
|
+
const explicit = /* @__PURE__ */ new Set();
|
|
92643
|
+
for (const skill of AGENT_SKILL_REGISTRY) {
|
|
92644
|
+
if (skillMatches(skill, normalizedText)) explicit.add(skill.id);
|
|
92645
|
+
}
|
|
92646
|
+
if (/\bgoogle\s+docs?\b/i.test(text) && availableToolNames.has("browser_execute_task")) {
|
|
92647
|
+
explicit.add("documents");
|
|
92648
|
+
explicit.add("browser-operator");
|
|
92649
|
+
}
|
|
92650
|
+
if (/\b(this|attached|local)\s+folder\b/i.test(text) || Boolean(input.selectedFolder) && /\bfolder\b/i.test(text)) {
|
|
92651
|
+
explicit.add("workspace");
|
|
92652
|
+
}
|
|
92653
|
+
if (/\b(ap|accounts?\s+payable)\b/i.test(text)) {
|
|
92654
|
+
explicit.add("data-quality");
|
|
92655
|
+
}
|
|
92656
|
+
if (isMarketDeskSignalTask(text, availableToolNames)) {
|
|
92657
|
+
explicit.delete("research");
|
|
92658
|
+
omitted.push({
|
|
92659
|
+
id: "research",
|
|
92660
|
+
reason: "market-desk signal tasks should use Market Desk tools before public research"
|
|
92661
|
+
});
|
|
92662
|
+
}
|
|
92663
|
+
const companionExpanded = /* @__PURE__ */ new Set();
|
|
92664
|
+
for (const id of sortSkillIds(explicit)) {
|
|
92665
|
+
const skill = byId.get(id);
|
|
92666
|
+
if (!skill) continue;
|
|
92667
|
+
for (const companionId of skill.companionSkills) {
|
|
92668
|
+
if (!explicit.has(companionId)) companionExpanded.add(companionId);
|
|
92669
|
+
}
|
|
92670
|
+
}
|
|
92671
|
+
const selected = [];
|
|
92672
|
+
for (const id of [
|
|
92673
|
+
...sortSkillIds(explicit),
|
|
92674
|
+
...sortSkillIds(companionExpanded)
|
|
92675
|
+
]) {
|
|
92676
|
+
const skill = byId.get(id);
|
|
92677
|
+
if (!skill) continue;
|
|
92678
|
+
const omittedReason = canUseSkillOnSurface(skill, input, availableToolNames);
|
|
92679
|
+
if (omittedReason) {
|
|
92680
|
+
omitted.push({ id, reason: omittedReason });
|
|
92681
|
+
continue;
|
|
92682
|
+
}
|
|
92683
|
+
if (selected.length >= maxSelected) {
|
|
92684
|
+
omitted.push({ id, reason: `max selected skills reached (${maxSelected})` });
|
|
92685
|
+
continue;
|
|
92686
|
+
}
|
|
92687
|
+
selected.push(skill);
|
|
92688
|
+
}
|
|
92689
|
+
return { metadataRows, selected, omitted };
|
|
92690
|
+
}
|
|
92691
|
+
var DEFAULT_MAX_SELECTED_SKILLS, BROWSER_TOOL_NAMES, CORE_PRIORITY, INTENT_PATTERNS;
|
|
92692
|
+
var init_skillSelector = __esm({
|
|
92693
|
+
"features/perchTerminal/agentPlatform/skills/skillSelector.ts"() {
|
|
92694
|
+
init_agentSkillRegistry();
|
|
92695
|
+
init_marketDeskAccess();
|
|
92696
|
+
DEFAULT_MAX_SELECTED_SKILLS = 4;
|
|
92697
|
+
BROWSER_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
92698
|
+
"browser_execute_task",
|
|
92699
|
+
"browser_observe",
|
|
92700
|
+
"browser_click",
|
|
92701
|
+
"browser_type",
|
|
92702
|
+
"browser_visual_click",
|
|
92703
|
+
"browser_focus_type",
|
|
92704
|
+
"browser_press_key",
|
|
92705
|
+
"browser_read",
|
|
92706
|
+
"browser_wait",
|
|
92707
|
+
"browser_navigate"
|
|
92708
|
+
]);
|
|
92709
|
+
CORE_PRIORITY = [
|
|
92710
|
+
"data-quality",
|
|
92711
|
+
"presentations",
|
|
92712
|
+
"spreadsheets",
|
|
92713
|
+
"documents",
|
|
92714
|
+
"pdf",
|
|
92715
|
+
"research",
|
|
92716
|
+
"diagrams",
|
|
92717
|
+
"workspace",
|
|
92718
|
+
"browser-operator",
|
|
92719
|
+
"skill-creator"
|
|
92720
|
+
];
|
|
92721
|
+
INTENT_PATTERNS = {
|
|
92722
|
+
"browser-operator": [
|
|
92723
|
+
/\b(browser|web\s+app|logged[-\s]?in|saas|portal|form)\b/i,
|
|
92724
|
+
/\b(gmail|google\s+docs?|google\s+calendar|notion|salesforce)\b/i
|
|
92725
|
+
],
|
|
92726
|
+
documents: [
|
|
92727
|
+
/\b(docx|word\s+file|google\s+docs?|memo|letter|report|redline|tracked\s+changes?|policy|formal\s+artifact)\b/i,
|
|
92728
|
+
/\b(create|write|draft|revise|edit|publish|deliver)\b.{0,48}\b(document|doc|memo|report|letter)\b/i
|
|
92729
|
+
],
|
|
92730
|
+
spreadsheets: [
|
|
92731
|
+
/\b(spreadsheet|xlsx|excel|workbook|csv|tsv|google\s+sheet|formula|pivot|reconciliation\s+tab|exception\s+tab|import\s+template)\b/i,
|
|
92732
|
+
/\b(row\s+count|totals?|tie[-\s]?out|sheet)\b/i
|
|
92733
|
+
],
|
|
92734
|
+
presentations: [
|
|
92735
|
+
/\b(deck|pptx|powerpoint|slides?|presentation|board\s+deck|executive\s+deck|pitch\s+deck|sales\s+deck|speaker\s+notes?)\b/i
|
|
92736
|
+
],
|
|
92737
|
+
pdf: [
|
|
92738
|
+
/\b(pdf|scanned\s+pdf|page\s+citation|pdf\s+table|split\s+pdf|merge\s+pdf|ocr|annual\s+report)\b/i,
|
|
92739
|
+
/\.pdf\b/i
|
|
92740
|
+
],
|
|
92741
|
+
research: [
|
|
92742
|
+
/\b(research|credible\s+sources?|current\s+source|citations?|source\s+comparison|scholarly|public\s+web|fact[-\s]?check|latest|recent|filing)\b/i,
|
|
92743
|
+
/\b(find|gather|compare|verify)\b.{0,48}\b(sources?|evidence|filings?)\b/i
|
|
92744
|
+
],
|
|
92745
|
+
diagrams: [
|
|
92746
|
+
/\b(diagram|mermaid|drawio|workflow\s+graph|org\s+chart|entity\s+network|control\s+graph|architecture\s+map|vendor[-\s]?risk\s+graph|nodes?\s+and\s+edges?)\b/i,
|
|
92747
|
+
/\b(graph|map)\b.{0,32}\b(risk|workflow|architecture|network|relationship)\b/i
|
|
92748
|
+
],
|
|
92749
|
+
workspace: [
|
|
92750
|
+
/\b(repo|codebase|local\s+folder|workspace|find\s+file|inspect\s+folder|search\s+files?|edit\s+file|source\s+inventory|project\s+files?)\b/i,
|
|
92751
|
+
/\b(this\s+repo|this\s+folder|attached\s+folder|in\s+this\s+workspace)\b/i
|
|
92752
|
+
],
|
|
92753
|
+
"data-quality": [
|
|
92754
|
+
/\b(data\s+quality|anomal(?:y|ies)|reconciliation|duplicate\s+(?:payment|invoice)|tie[-\s]?out|row\s+totals?|audit\s+exceptions?|vendor\s+risk|outliers?|missing\s+receipt|cost\s+anomal(?:y|ies))\b/i,
|
|
92755
|
+
/\b(audit|reconcile|profile|clean)\b.{0,56}\b(ap|accounts?\s+payable|payments?|invoices?|vendors?|data|folder)\b/i
|
|
92756
|
+
],
|
|
92757
|
+
"skill-creator": [
|
|
92758
|
+
/\b(skill\s+creator|create\s+(?:a\s+)?skill|skill\.md|agent\s+skill|skill\s+validation|trigger\s+collision|skill\s+test|skill\s+authoring|perch\s+skill)\b/i
|
|
92759
|
+
]
|
|
92760
|
+
};
|
|
92761
|
+
}
|
|
92762
|
+
});
|
|
92763
|
+
|
|
92164
92764
|
// features/perchTerminal/runtime/context/tokenEstimates.ts
|
|
92165
92765
|
function estimateTokensForLane(text, lane, modelTokenize) {
|
|
92166
92766
|
return countTokensForLane(
|
|
@@ -92237,6 +92837,26 @@ function assembleContext(input) {
|
|
|
92237
92837
|
const contextCompaction = input.threadId ? getThreadSessionFromMemory(input.threadId)?.contextCompaction ?? null : null;
|
|
92238
92838
|
const threadSession = input.threadId ? getThreadSessionFromMemory(input.threadId) : null;
|
|
92239
92839
|
const coreSystem = buildCoreSystemSection(input);
|
|
92840
|
+
const selectedSkillPack = selectAgentSkills({
|
|
92841
|
+
userMessage: input.trimmedInput,
|
|
92842
|
+
currentMode: input.chatMode,
|
|
92843
|
+
personaId: input.personaId ?? null,
|
|
92844
|
+
selectedFiles: [
|
|
92845
|
+
...input.workspaceFileResolution?.matchedFiles.map(
|
|
92846
|
+
(file) => file.relativePath
|
|
92847
|
+
) ?? [],
|
|
92848
|
+
...(input.localSources ?? []).slice(0, 12).map((source) => source.relativePath || source.fileName)
|
|
92849
|
+
],
|
|
92850
|
+
selectedFolder: input.activeRootPath,
|
|
92851
|
+
sourceSummary: [
|
|
92852
|
+
input.selectedSourceId ? `selected source ${input.selectedSourceId}` : "",
|
|
92853
|
+
input.folderIndexSummary ? `folder indexed ${input.folderIndexSummary.totalFiles} files` : "",
|
|
92854
|
+
input.selectedSourceBundle?.fileName ?? ""
|
|
92855
|
+
].filter(Boolean).join("\n"),
|
|
92856
|
+
availableToolNames: input.enabledToolNames ?? [],
|
|
92857
|
+
surface: input.skillSelectionSurface ?? (input.cliLocalTools === true && !input.desktopConnected ? "cli" : "gui")
|
|
92858
|
+
});
|
|
92859
|
+
const selectedSkillsSection = buildSelectedSkillsSection(selectedSkillPack);
|
|
92240
92860
|
const selectedModelSection = buildSelectedModelSection(
|
|
92241
92861
|
input.selectedModel ?? null
|
|
92242
92862
|
);
|
|
@@ -92300,6 +92920,7 @@ function assembleContext(input) {
|
|
|
92300
92920
|
content: coreSystem,
|
|
92301
92921
|
reason: "Core operator instructions for the current turn."
|
|
92302
92922
|
},
|
|
92923
|
+
selectedSkillsSection,
|
|
92303
92924
|
...toolsJson ? [
|
|
92304
92925
|
{
|
|
92305
92926
|
id: "tool-schemas",
|
|
@@ -92401,6 +93022,7 @@ function assembleContext(input) {
|
|
|
92401
93022
|
});
|
|
92402
93023
|
const systemPrompt = systemSections.filter((row) => row.trim()).join("\n\n");
|
|
92403
93024
|
const sectionBreakdown = buildSectionBreakdown(rows);
|
|
93025
|
+
const selectedSkillIds = selectedSkillPack.selected.map((skill) => skill.id);
|
|
92404
93026
|
const totalContextTokens = rows.filter((row) => row.status !== "reserved").reduce((sum, row) => sum + row.estimatedTokens, 0);
|
|
92405
93027
|
const compactedCount = rows.filter(
|
|
92406
93028
|
(row) => row.status === "sent_compacted"
|
|
@@ -92439,7 +93061,9 @@ function assembleContext(input) {
|
|
|
92439
93061
|
activeRootPath: input.activeRootPath,
|
|
92440
93062
|
recentMessageCount: input.recentMessages.length,
|
|
92441
93063
|
selectedModel: input.selectedModel ?? null,
|
|
92442
|
-
untrustedContextPresent
|
|
93064
|
+
untrustedContextPresent,
|
|
93065
|
+
selectedSkills: selectedSkillIds,
|
|
93066
|
+
omittedSkills: selectedSkillPack.omitted
|
|
92443
93067
|
},
|
|
92444
93068
|
warnings
|
|
92445
93069
|
},
|
|
@@ -92468,6 +93092,56 @@ function buildSelectedModelSection(selectedModel) {
|
|
|
92468
93092
|
}
|
|
92469
93093
|
};
|
|
92470
93094
|
}
|
|
93095
|
+
function buildSelectedSkillsSection(pack) {
|
|
93096
|
+
const selectedSkillIds = pack.selected.map((skill) => skill.id);
|
|
93097
|
+
const metadata = {
|
|
93098
|
+
selectedSkillIds,
|
|
93099
|
+
selectedSkillCount: pack.selected.length,
|
|
93100
|
+
omitted: pack.omitted,
|
|
93101
|
+
metadataRows: pack.metadataRows
|
|
93102
|
+
};
|
|
93103
|
+
if (pack.selected.length === 0) {
|
|
93104
|
+
return {
|
|
93105
|
+
id: "selected-skills",
|
|
93106
|
+
lane: "selected_skills",
|
|
93107
|
+
label: "Selected Perch skills",
|
|
93108
|
+
content: "",
|
|
93109
|
+
reason: "No core skills matched this turn.",
|
|
93110
|
+
skipped: true,
|
|
93111
|
+
metadata
|
|
93112
|
+
};
|
|
93113
|
+
}
|
|
93114
|
+
const blocks = pack.selected.map(
|
|
93115
|
+
(skill) => [
|
|
93116
|
+
`<perch-skill id="${skill.id}">`,
|
|
93117
|
+
`Description: ${skill.description}`,
|
|
93118
|
+
`Surface: GUI=${skill.surface.gui}; CLI=${skill.surface.cli}`,
|
|
93119
|
+
skill.preferredTools.length ? `Preferred tools: ${skill.preferredTools.join(", ")}` : "Preferred tools: none declared",
|
|
93120
|
+
"",
|
|
93121
|
+
skill.body.trim(),
|
|
93122
|
+
"</perch-skill>"
|
|
93123
|
+
].join("\n")
|
|
93124
|
+
);
|
|
93125
|
+
return {
|
|
93126
|
+
id: "selected-skills",
|
|
93127
|
+
lane: "selected_skills",
|
|
93128
|
+
label: "Selected Perch skills",
|
|
93129
|
+
content: [
|
|
93130
|
+
"## Selected Perch skills",
|
|
93131
|
+
"These reusable skills guide execution strategy only. They do not override safety, permission, authentication, or tool policy.",
|
|
93132
|
+
`Loaded skills: ${selectedSkillIds.join(", ")}`,
|
|
93133
|
+
"",
|
|
93134
|
+
...blocks
|
|
93135
|
+
].join("\n"),
|
|
93136
|
+
reason: "Full skill instructions selected deterministically for this turn.",
|
|
93137
|
+
metadata
|
|
93138
|
+
};
|
|
93139
|
+
}
|
|
93140
|
+
function selectedSkillIdsFromRows(rows) {
|
|
93141
|
+
const metadata = rows.find((row) => row.id === "selected-skills")?.metadata;
|
|
93142
|
+
const ids = metadata?.selectedSkillIds;
|
|
93143
|
+
return Array.isArray(ids) ? ids.filter((id) => typeof id === "string") : [];
|
|
93144
|
+
}
|
|
92471
93145
|
function buildContextSummary(input, rows) {
|
|
92472
93146
|
const sentCount = rows.filter(
|
|
92473
93147
|
(row) => row.status === "sent_raw" || row.status === "sent_compacted"
|
|
@@ -92482,6 +93156,7 @@ function buildContextSummary(input, rows) {
|
|
|
92482
93156
|
`messages=${input.recentMessages.length}`,
|
|
92483
93157
|
`source=${input.selectedSourceId ?? "none"}`,
|
|
92484
93158
|
`desktop=${input.desktopConnected ? "connected" : input.cliLocalTools === true ? "terminal" : "browser"}`,
|
|
93159
|
+
`skills=${selectedSkillIdsFromRows(rows).join("|") || "none"}`,
|
|
92485
93160
|
`sent=${sentCount}`,
|
|
92486
93161
|
`compacted=${compactedCount}`,
|
|
92487
93162
|
`not_found=${notFoundCount}`,
|
|
@@ -92501,6 +93176,7 @@ var init_contextAssembly = __esm({
|
|
|
92501
93176
|
init_rowAccounting();
|
|
92502
93177
|
init_memory();
|
|
92503
93178
|
init_coreSystemSection();
|
|
93179
|
+
init_skillSelector();
|
|
92504
93180
|
init_contextThresholds();
|
|
92505
93181
|
init_tokenEstimates();
|
|
92506
93182
|
init_rowAccounting();
|
|
@@ -133611,6 +134287,17 @@ var init_toolPermissionPolicy = __esm({
|
|
|
133611
134287
|
TOOL_NAMES.prepareAPEvidence,
|
|
133612
134288
|
TOOL_NAMES.queryAPCases,
|
|
133613
134289
|
TOOL_NAMES.renderAPControlGraph,
|
|
134290
|
+
TOOL_NAMES.runManagedPlaybook,
|
|
134291
|
+
TOOL_NAMES.runSuite,
|
|
134292
|
+
TOOL_NAMES.listSuiteCatalog,
|
|
134293
|
+
TOOL_NAMES.proposeSuitePlan,
|
|
134294
|
+
TOOL_NAMES.executeSuitePlan,
|
|
134295
|
+
TOOL_NAMES.proposeWork,
|
|
134296
|
+
TOOL_NAMES.executeWork,
|
|
134297
|
+
TOOL_NAMES.sendWorkerMessage,
|
|
134298
|
+
TOOL_NAMES.taskStop,
|
|
134299
|
+
TOOL_NAMES.spawnWorker,
|
|
134300
|
+
TOOL_NAMES.dispatchAgent,
|
|
133614
134301
|
TOOL_NAMES.runSandboxCode
|
|
133615
134302
|
];
|
|
133616
134303
|
CLI_LOCAL_TOOL_NAME_SET = new Set(CLI_LOCAL_TOOL_NAMES);
|
|
@@ -168151,7 +168838,7 @@ function template(text, settings, oldSettings) {
|
|
|
168151
168838
|
var index = 0;
|
|
168152
168839
|
var source = "__p+='";
|
|
168153
168840
|
text.replace(matcher2, function(match, escape4, interpolate, evaluate, offset) {
|
|
168154
|
-
source += text.slice(index, offset).replace(
|
|
168841
|
+
source += text.slice(index, offset).replace(escapeRegExp3, escapeChar);
|
|
168155
168842
|
index = offset + match.length;
|
|
168156
168843
|
if (escape4) {
|
|
168157
168844
|
source += "'+\n((__t=(" + escape4 + "))==null?'':_.escape(__t))+\n'";
|
|
@@ -168186,7 +168873,7 @@ function template(text, settings, oldSettings) {
|
|
|
168186
168873
|
template2.source = "function(" + argument + "){\n" + source + "}";
|
|
168187
168874
|
return template2;
|
|
168188
168875
|
}
|
|
168189
|
-
var noMatch, escapes,
|
|
168876
|
+
var noMatch, escapes, escapeRegExp3, bareIdentifier;
|
|
168190
168877
|
var init_template = __esm({
|
|
168191
168878
|
"node_modules/underscore/modules/template.js"() {
|
|
168192
168879
|
init_defaults();
|
|
@@ -168201,7 +168888,7 @@ var init_template = __esm({
|
|
|
168201
168888
|
"\u2028": "u2028",
|
|
168202
168889
|
"\u2029": "u2029"
|
|
168203
168890
|
};
|
|
168204
|
-
|
|
168891
|
+
escapeRegExp3 = /\\|'|\r|\n|\u2028|\u2029/g;
|
|
168205
168892
|
bareIdentifier = /^\s*(\w|\$)+\s*$/;
|
|
168206
168893
|
}
|
|
168207
168894
|
});
|
|
@@ -199949,7 +200636,6 @@ function containsBrowserDeliveryTask(tasks) {
|
|
|
199949
200636
|
var BROWSER_DELIVERY_ROLE_IDS;
|
|
199950
200637
|
var init_browserDeliveryLock = __esm({
|
|
199951
200638
|
"features/perchTerminal/agentPlatform/browserDeliveryLock.ts"() {
|
|
199952
|
-
"use strict";
|
|
199953
200639
|
BROWSER_DELIVERY_ROLE_IDS = /* @__PURE__ */ new Set([
|
|
199954
200640
|
"doc_writer",
|
|
199955
200641
|
"email_sender",
|
|
@@ -201862,7 +202548,7 @@ function lifecycleState(ctx) {
|
|
|
201862
202548
|
}
|
|
201863
202549
|
return state;
|
|
201864
202550
|
}
|
|
201865
|
-
function
|
|
202551
|
+
function normalizeText2(value) {
|
|
201866
202552
|
if (typeof value === "string") return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
201867
202553
|
if (value === null || value === void 0) return "";
|
|
201868
202554
|
try {
|
|
@@ -201873,7 +202559,7 @@ function normalizeText(value) {
|
|
|
201873
202559
|
}
|
|
201874
202560
|
function explicitRetryRequested(tasks) {
|
|
201875
202561
|
const text = tasks.map((task) => `${task.objective}
|
|
201876
|
-
${
|
|
202562
|
+
${normalizeText2(task.context)}`).join("\n");
|
|
201877
202563
|
return /\b(retry|re-run|rerun|run again|fresh pass|fresh read|repeat|redo)\b/i.test(text);
|
|
201878
202564
|
}
|
|
201879
202565
|
function isSourceReaderLifecycleRole(roleId) {
|
|
@@ -201884,7 +202570,7 @@ function isSourceReaderLifecycleRole(roleId) {
|
|
|
201884
202570
|
}
|
|
201885
202571
|
function extractSourceScopes(task) {
|
|
201886
202572
|
const text = `${task.objective}
|
|
201887
|
-
${
|
|
202573
|
+
${normalizeText2(task.context)}`;
|
|
201888
202574
|
const scopes = /* @__PURE__ */ new Set();
|
|
201889
202575
|
const pathPattern = /\b(?:\d{2}-[a-z0-9_-]+|[a-z0-9_-]+\/[a-z0-9_ .&/-]+)(?:\/[a-z0-9_ .&-]+)*/gi;
|
|
201890
202576
|
for (const match of text.matchAll(pathPattern)) {
|
|
@@ -201894,14 +202580,14 @@ ${normalizeText(task.context)}`;
|
|
|
201894
202580
|
}
|
|
201895
202581
|
if (raw.length >= 4) scopes.add(raw.toLowerCase());
|
|
201896
202582
|
}
|
|
201897
|
-
if (scopes.size === 0) scopes.add(
|
|
202583
|
+
if (scopes.size === 0) scopes.add(normalizeText2(task.objective).slice(0, 120));
|
|
201898
202584
|
return [...scopes].sort();
|
|
201899
202585
|
}
|
|
201900
202586
|
function taskSignature(task) {
|
|
201901
202587
|
return JSON.stringify({
|
|
201902
202588
|
roleId: task.roleId,
|
|
201903
|
-
objective:
|
|
201904
|
-
context:
|
|
202589
|
+
objective: normalizeText2(task.objective),
|
|
202590
|
+
context: normalizeText2(task.context)
|
|
201905
202591
|
});
|
|
201906
202592
|
}
|
|
201907
202593
|
function batchSignature(tasks) {
|
|
@@ -217660,7 +218346,7 @@ function isBrowserSnapshotToolResult(messages, index) {
|
|
|
217660
218346
|
const toolName = toolNameForMessage(messages, index);
|
|
217661
218347
|
const text = messageContentText(msg);
|
|
217662
218348
|
if (!text.includes("snapshot")) return false;
|
|
217663
|
-
if (toolName &&
|
|
218349
|
+
if (toolName && BROWSER_TOOL_NAMES2.has(toolName)) return true;
|
|
217664
218350
|
try {
|
|
217665
218351
|
const parsed = JSON.parse(text);
|
|
217666
218352
|
return typeof parsed.snapshot === "string" && parsed.snapshot.length > 200;
|
|
@@ -218135,7 +218821,7 @@ async function prepareLoopMessagesForSend(input) {
|
|
|
218135
218821
|
microcompactedToolResults
|
|
218136
218822
|
};
|
|
218137
218823
|
}
|
|
218138
|
-
var OPERATOR_SCREENSHOT_MARKER2, KEPT_SNAPSHOT_MAX_CHARS, KEPT_SNAPSHOT_TRUNCATED_MARKER,
|
|
218824
|
+
var OPERATOR_SCREENSHOT_MARKER2, KEPT_SNAPSHOT_MAX_CHARS, KEPT_SNAPSHOT_TRUNCATED_MARKER, BROWSER_TOOL_NAMES2, RECENT_MESSAGES_KEEP_COUNT, RECENT_TOOL_RESULTS_KEEP_COUNT, POST_COMPACT_TARGET_TOKENS, POST_COMPACT_MIN_TARGET_TOKENS, POST_COMPACT_MAX_TARGET_TOKENS, POST_COMPACT_RECENT_TAIL_MIN_TOKENS, POST_COMPACT_RECENT_TAIL_MAX_TOKENS, MICROCOMPACT_CLEARED_MARKER, COMPACT_SUMMARY_RESERVE_TOKENS, COMPACT_SYSTEM_PROMPT;
|
|
218139
218825
|
var init_contextLoopCompaction = __esm({
|
|
218140
218826
|
"features/perchTerminal/runtime/services/contextLoopCompaction.ts"() {
|
|
218141
218827
|
"use strict";
|
|
@@ -218150,7 +218836,7 @@ var init_contextLoopCompaction = __esm({
|
|
|
218150
218836
|
OPERATOR_SCREENSHOT_MARKER2 = "[operator-screen]";
|
|
218151
218837
|
KEPT_SNAPSHOT_MAX_CHARS = 12e3;
|
|
218152
218838
|
KEPT_SNAPSHOT_TRUNCATED_MARKER = "[snapshot truncated]";
|
|
218153
|
-
|
|
218839
|
+
BROWSER_TOOL_NAMES2 = /* @__PURE__ */ new Set([
|
|
218154
218840
|
TOOL_NAMES.browserNavigate,
|
|
218155
218841
|
TOOL_NAMES.browserObserve,
|
|
218156
218842
|
TOOL_NAMES.browserClick,
|
|
@@ -221650,7 +222336,7 @@ var init_preTurnRetrieval = __esm({
|
|
|
221650
222336
|
// features/perchTerminal/rag/chunking.ts
|
|
221651
222337
|
import { createHash as createHash2 } from "crypto";
|
|
221652
222338
|
function buildRetrievalChunks(text, metadata, options = {}) {
|
|
221653
|
-
const normalized =
|
|
222339
|
+
const normalized = normalizeText3(text);
|
|
221654
222340
|
if (!normalized) return [];
|
|
221655
222341
|
const targetChars = Math.max(400, (options.targetTokens ?? DEFAULT_TARGET_TOKENS) * APPROX_CHARS_PER_TOKEN);
|
|
221656
222342
|
const overlapChars = Math.max(0, Math.min(targetChars / 2, (options.overlapTokens ?? DEFAULT_OVERLAP_TOKENS) * APPROX_CHARS_PER_TOKEN));
|
|
@@ -221680,7 +222366,7 @@ function buildRetrievalChunks(text, metadata, options = {}) {
|
|
|
221680
222366
|
return chunk2;
|
|
221681
222367
|
});
|
|
221682
222368
|
}
|
|
221683
|
-
function
|
|
222369
|
+
function normalizeText3(text) {
|
|
221684
222370
|
return text.replace(/\r\n/g, "\n").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
221685
222371
|
}
|
|
221686
222372
|
function stableContentHash(value) {
|
|
@@ -224323,6 +225009,8 @@ function buildClientContextSnapshot(input) {
|
|
|
224323
225009
|
compacted: context.snapshot.compacted,
|
|
224324
225010
|
chatMode: input.input.chatMode,
|
|
224325
225011
|
selectedSourceId: input.input.selectedSourceId,
|
|
225012
|
+
selectedSkills: extractSelectedSkills(context),
|
|
225013
|
+
omittedSkills: extractOmittedSkills(context),
|
|
224326
225014
|
desktopConnected: input.input.desktopConnected,
|
|
224327
225015
|
cliLocalTools: input.input.cliLocalTools === true,
|
|
224328
225016
|
sectionBreakdown: context.snapshot.sectionBreakdown,
|
|
@@ -224361,6 +225049,23 @@ function buildClientContextSnapshot(input) {
|
|
|
224361
225049
|
} : {}
|
|
224362
225050
|
};
|
|
224363
225051
|
}
|
|
225052
|
+
function extractSelectedSkills(context) {
|
|
225053
|
+
const metadata = context.snapshot.rows.find(
|
|
225054
|
+
(row) => row.id === "selected-skills"
|
|
225055
|
+
)?.metadata;
|
|
225056
|
+
const ids = metadata?.selectedSkillIds;
|
|
225057
|
+
return Array.isArray(ids) ? ids.filter((id) => typeof id === "string") : [];
|
|
225058
|
+
}
|
|
225059
|
+
function extractOmittedSkills(context) {
|
|
225060
|
+
const metadata = context.snapshot.rows.find(
|
|
225061
|
+
(row) => row.id === "selected-skills"
|
|
225062
|
+
)?.metadata;
|
|
225063
|
+
const omitted = metadata?.omitted;
|
|
225064
|
+
if (!Array.isArray(omitted)) return [];
|
|
225065
|
+
return omitted.filter(
|
|
225066
|
+
(item) => typeof item === "object" && item !== null && typeof item.id === "string" && typeof item.reason === "string"
|
|
225067
|
+
);
|
|
225068
|
+
}
|
|
224364
225069
|
var init_turnContextSnapshot = __esm({
|
|
224365
225070
|
"features/perchTerminal/runtime/turn/turnContextSnapshot.ts"() {
|
|
224366
225071
|
"use strict";
|
|
@@ -259813,7 +260518,7 @@ var require_websocket = __commonJS({
|
|
|
259813
260518
|
var http2 = __require("http");
|
|
259814
260519
|
var net = __require("net");
|
|
259815
260520
|
var tls = __require("tls");
|
|
259816
|
-
var { randomBytes, createHash:
|
|
260521
|
+
var { randomBytes, createHash: createHash5 } = __require("crypto");
|
|
259817
260522
|
var { Duplex, Readable } = __require("stream");
|
|
259818
260523
|
var { URL: URL2 } = __require("url");
|
|
259819
260524
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -260481,7 +261186,7 @@ var require_websocket = __commonJS({
|
|
|
260481
261186
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
260482
261187
|
return;
|
|
260483
261188
|
}
|
|
260484
|
-
const digest =
|
|
261189
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
260485
261190
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
260486
261191
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
260487
261192
|
return;
|
|
@@ -260850,7 +261555,7 @@ var require_websocket_server = __commonJS({
|
|
|
260850
261555
|
var EventEmitter3 = __require("events");
|
|
260851
261556
|
var http2 = __require("http");
|
|
260852
261557
|
var { Duplex } = __require("stream");
|
|
260853
|
-
var { createHash:
|
|
261558
|
+
var { createHash: createHash5 } = __require("crypto");
|
|
260854
261559
|
var extension2 = require_extension();
|
|
260855
261560
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
260856
261561
|
var subprotocol2 = require_subprotocol();
|
|
@@ -261157,7 +261862,7 @@ var require_websocket_server = __commonJS({
|
|
|
261157
261862
|
);
|
|
261158
261863
|
}
|
|
261159
261864
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
261160
|
-
const digest =
|
|
261865
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
261161
261866
|
const headers = [
|
|
261162
261867
|
"HTTP/1.1 101 Switching Protocols",
|
|
261163
261868
|
"Upgrade: websocket",
|
|
@@ -283093,6 +283798,7 @@ __export(perch_cli_exports, {
|
|
|
283093
283798
|
runPerchCli: () => runPerchCli
|
|
283094
283799
|
});
|
|
283095
283800
|
import fs14 from "node:fs";
|
|
283801
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
283096
283802
|
import os5 from "node:os";
|
|
283097
283803
|
import path14 from "node:path";
|
|
283098
283804
|
import readline from "node:readline/promises";
|
|
@@ -283118,12 +283824,17 @@ ${HELP_TEXT}`);
|
|
|
283118
283824
|
if (parsed.domain === "auth") {
|
|
283119
283825
|
return runAuthCommand(parsed, writer);
|
|
283120
283826
|
}
|
|
283827
|
+
if (parsed.domain === "skills") {
|
|
283828
|
+
writer.stdout(renderCliSkills(parsed.name));
|
|
283829
|
+
return 0;
|
|
283830
|
+
}
|
|
283121
283831
|
if (parsed.domain === "run") {
|
|
283122
283832
|
const connectModelProxy = deps.connectModelProxy ?? connectCliModelProxy;
|
|
283123
283833
|
const connection = await connectModelProxy({ appUrl: parsed.appUrl });
|
|
283124
283834
|
try {
|
|
283125
283835
|
const threadId = parsed.threadId?.trim() || "cli-default";
|
|
283126
|
-
const
|
|
283836
|
+
const threadScopeKey = await resolveCliThreadScopeKey(connection);
|
|
283837
|
+
const persisted = await hydrateCliThreadState(threadId, threadScopeKey);
|
|
283127
283838
|
const hostedContext = await fetchCliHostedContext(connection, {
|
|
283128
283839
|
query: parsed.prompt,
|
|
283129
283840
|
threadId
|
|
@@ -283165,6 +283876,7 @@ ${HELP_TEXT}`);
|
|
|
283165
283876
|
});
|
|
283166
283877
|
await persistCliThreadState({
|
|
283167
283878
|
threadId: result3.threadId,
|
|
283879
|
+
threadScopeKey,
|
|
283168
283880
|
recentMessages: nextRecentMessages,
|
|
283169
283881
|
contextSnapshot: result3.contextSnapshot ?? persisted?.contextSnapshot ?? null
|
|
283170
283882
|
});
|
|
@@ -283222,6 +283934,7 @@ function parsePerchCli(argv) {
|
|
|
283222
283934
|
if (domain === "login") return { ok: true, domain: "auth", action: "login", ...global2.appUrl ? { appUrl: global2.appUrl } : {} };
|
|
283223
283935
|
if (domain === "logout") return { ok: true, domain: "auth", action: "logout" };
|
|
283224
283936
|
if (domain === "status") return { ok: true, domain: "auth", action: "status" };
|
|
283937
|
+
if (domain === "skills") return { ok: true, domain: "skills", ...action ? { name: action } : {} };
|
|
283225
283938
|
if (domain !== "ap" && domain !== "test") return { ok: false, error: `Unknown domain: ${domain ?? "(missing)"}` };
|
|
283226
283939
|
if (domain === "test") {
|
|
283227
283940
|
if (action !== "ap") return { ok: false, error: `Unknown test command: ${action ?? "(missing)"}` };
|
|
@@ -283439,14 +284152,15 @@ async function runReadlineInteractivePerchCli(writer, deps, options) {
|
|
|
283439
284152
|
terminal: true
|
|
283440
284153
|
});
|
|
283441
284154
|
const state = createInteractiveCliState(options);
|
|
283442
|
-
await hydrateInteractiveCliState(state);
|
|
283443
284155
|
const connectModelProxy = deps.connectModelProxy ?? connectCliModelProxy;
|
|
283444
284156
|
let connection = await connectModelProxy({ appUrl: state.appUrl });
|
|
283445
284157
|
if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
|
|
284158
|
+
await syncInteractiveCliThreadScope(state, connection, { force: true });
|
|
283446
284159
|
const reconnect = async () => {
|
|
283447
284160
|
connection.restore();
|
|
283448
284161
|
connection = await connectModelProxy({ appUrl: state.appUrl });
|
|
283449
284162
|
if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
|
|
284163
|
+
await syncInteractiveCliThreadScope(state, connection);
|
|
283450
284164
|
};
|
|
283451
284165
|
writer.stdout(renderInteractiveStartup(state, connection));
|
|
283452
284166
|
try {
|
|
@@ -283532,14 +284246,15 @@ async function runInkInteractivePerchCli(writer, deps, options) {
|
|
|
283532
284246
|
init_build2().then(() => build_exports)
|
|
283533
284247
|
]);
|
|
283534
284248
|
const state = createInteractiveCliState(options);
|
|
283535
|
-
await hydrateInteractiveCliState(state);
|
|
283536
284249
|
const connectModelProxy = deps.connectModelProxy ?? connectCliModelProxy;
|
|
283537
284250
|
let connection = await connectModelProxy({ appUrl: state.appUrl });
|
|
283538
284251
|
if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
|
|
284252
|
+
await syncInteractiveCliThreadScope(state, connection, { force: true });
|
|
283539
284253
|
const reconnect = async () => {
|
|
283540
284254
|
connection.restore();
|
|
283541
284255
|
connection = await connectModelProxy({ appUrl: state.appUrl });
|
|
283542
284256
|
if (!state.appUrl && connection.appUrl) state.appUrl = connection.appUrl;
|
|
284257
|
+
await syncInteractiveCliThreadScope(state, connection);
|
|
283543
284258
|
};
|
|
283544
284259
|
const runTurn = deps.runCliTurn ?? runPerchCliTurn;
|
|
283545
284260
|
const instance = Ink2.render(
|
|
@@ -284254,6 +284969,9 @@ async function runInteractiveSlashCommand(input) {
|
|
|
284254
284969
|
));
|
|
284255
284970
|
return "continue";
|
|
284256
284971
|
}
|
|
284972
|
+
case "skills":
|
|
284973
|
+
input.writer.stdout(renderCliSkills(parsed.value));
|
|
284974
|
+
return "continue";
|
|
284257
284975
|
case "context":
|
|
284258
284976
|
input.writer.stdout(renderCliContextDetails(input.state.contextSnapshot));
|
|
284259
284977
|
return "continue";
|
|
@@ -284340,7 +285058,7 @@ async function runInteractiveSlashCommand(input) {
|
|
|
284340
285058
|
input.state.contextSnapshot = null;
|
|
284341
285059
|
input.state.persistedThreadUpdatedAt = null;
|
|
284342
285060
|
clearThreadSession(input.state.threadId);
|
|
284343
|
-
await deleteCliThreadState(input.state.threadId);
|
|
285061
|
+
await deleteCliThreadState(input.state.threadId, input.state.threadScopeKey);
|
|
284344
285062
|
writeModeLine(input.writer, "memory", "cleared");
|
|
284345
285063
|
return "continue";
|
|
284346
285064
|
case "login":
|
|
@@ -284373,6 +285091,8 @@ function parseInteractiveSlashCommand(input) {
|
|
|
284373
285091
|
return { ok: true, kind: "help" };
|
|
284374
285092
|
case "status":
|
|
284375
285093
|
return { ok: true, kind: "status" };
|
|
285094
|
+
case "skills":
|
|
285095
|
+
return { ok: true, kind: "skills", ...value ? { value } : {} };
|
|
284376
285096
|
case "context":
|
|
284377
285097
|
return { ok: true, kind: "context" };
|
|
284378
285098
|
case "memory-audit":
|
|
@@ -284428,6 +285148,7 @@ function renderInteractiveStatus(state, connection, session, workspaceId) {
|
|
|
284428
285148
|
["connection", connectionStatus],
|
|
284429
285149
|
["memory", renderCliMemoryAvailability(state.cwd, workspaceId ?? null, signedIn)],
|
|
284430
285150
|
["tools", renderCliCapabilityCount(state, workspaceId ?? null)],
|
|
285151
|
+
["skills", renderCliLoadedSkills(state.contextSnapshot)],
|
|
284431
285152
|
["permission", state.permissionMode],
|
|
284432
285153
|
["mode", state.chatMode],
|
|
284433
285154
|
["persona", state.personaId],
|
|
@@ -284458,6 +285179,43 @@ function renderCliCapabilityCount(state, workspaceId) {
|
|
|
284458
285179
|
}).length;
|
|
284459
285180
|
return `${count} visible`;
|
|
284460
285181
|
}
|
|
285182
|
+
function renderCliLoadedSkills(snapshot) {
|
|
285183
|
+
const skills = snapshot?.selectedSkills ?? [];
|
|
285184
|
+
return skills.length > 0 ? skills.join(", ") : "none loaded";
|
|
285185
|
+
}
|
|
285186
|
+
function renderCliSkills(name) {
|
|
285187
|
+
const color = shouldUseCliColor();
|
|
285188
|
+
if (name) {
|
|
285189
|
+
const skill = getAgentSkillManifest(name);
|
|
285190
|
+
if (!skill) {
|
|
285191
|
+
return `Unknown skill: ${name}
|
|
285192
|
+
Run /skills to list available skills.
|
|
285193
|
+
`;
|
|
285194
|
+
}
|
|
285195
|
+
return [
|
|
285196
|
+
`${paint(skill.name, "accent", color)}`,
|
|
285197
|
+
skill.description,
|
|
285198
|
+
`surface: GUI=${skill.surface.gui}; CLI=${skill.surface.cli}`,
|
|
285199
|
+
skill.triggerHints.length ? `triggers: ${skill.triggerHints.join(", ")}` : "triggers: none",
|
|
285200
|
+
skill.companionSkills.length ? `companions: ${skill.companionSkills.join(", ")}` : "companions: none",
|
|
285201
|
+
"",
|
|
285202
|
+
skill.body.trim(),
|
|
285203
|
+
""
|
|
285204
|
+
].join("\n");
|
|
285205
|
+
}
|
|
285206
|
+
const rows = listAgentSkillMetadataRows();
|
|
285207
|
+
return [
|
|
285208
|
+
"Perch core skills",
|
|
285209
|
+
...rows.map(
|
|
285210
|
+
(skill) => [
|
|
285211
|
+
`- ${skill.id}`,
|
|
285212
|
+
` ${skill.description}`,
|
|
285213
|
+
` surface: GUI=${skill.surface.gui}; CLI=${skill.surface.cli}`
|
|
285214
|
+
].join("\n")
|
|
285215
|
+
),
|
|
285216
|
+
""
|
|
285217
|
+
].join("\n");
|
|
285218
|
+
}
|
|
284461
285219
|
function renderInteractiveStartup(state, connection) {
|
|
284462
285220
|
const color = shouldUseCliColor();
|
|
284463
285221
|
const auth = renderCliAuthSummary(connection);
|
|
@@ -284539,6 +285297,7 @@ function createInteractiveCliState(options) {
|
|
|
284539
285297
|
personaId: options.personaId ?? "saffron",
|
|
284540
285298
|
permissionMode: options.permissionMode ?? "default",
|
|
284541
285299
|
threadId: options.threadId?.trim() || "cli-default",
|
|
285300
|
+
threadScopeKey: null,
|
|
284542
285301
|
desktopConnected: options.desktopConnected ?? false,
|
|
284543
285302
|
cliLocalTools: options.cliLocalTools ?? true,
|
|
284544
285303
|
appUrl: resolveCliAppUrl(options.appUrl ?? null, null),
|
|
@@ -284548,14 +285307,25 @@ function createInteractiveCliState(options) {
|
|
|
284548
285307
|
};
|
|
284549
285308
|
}
|
|
284550
285309
|
async function hydrateInteractiveCliState(state) {
|
|
284551
|
-
const persisted = await hydrateCliThreadState(state.threadId);
|
|
285310
|
+
const persisted = await hydrateCliThreadState(state.threadId, state.threadScopeKey);
|
|
284552
285311
|
if (!persisted) return;
|
|
284553
285312
|
state.recentMessages = persisted.recentMessages;
|
|
284554
285313
|
state.contextSnapshot = persisted.contextSnapshot;
|
|
284555
285314
|
state.persistedThreadUpdatedAt = persisted.updatedAt;
|
|
284556
285315
|
}
|
|
284557
|
-
async function
|
|
284558
|
-
const
|
|
285316
|
+
async function syncInteractiveCliThreadScope(state, connection, options = {}) {
|
|
285317
|
+
const nextScopeKey = await resolveCliThreadScopeKey(connection);
|
|
285318
|
+
if (!options.force && state.threadScopeKey === nextScopeKey) return;
|
|
285319
|
+
state.threadScopeKey = nextScopeKey;
|
|
285320
|
+
state.recentMessages = [];
|
|
285321
|
+
state.contextSnapshot = null;
|
|
285322
|
+
state.persistedThreadUpdatedAt = null;
|
|
285323
|
+
clearThreadSession(state.threadId);
|
|
285324
|
+
await hydrateInteractiveCliState(state);
|
|
285325
|
+
}
|
|
285326
|
+
async function hydrateCliThreadState(threadId, threadScopeKey) {
|
|
285327
|
+
const persisted = await readCliThreadState(threadId, threadScopeKey);
|
|
285328
|
+
clearThreadSession(threadId);
|
|
284559
285329
|
if (!persisted) return null;
|
|
284560
285330
|
if (persisted.threadSession) {
|
|
284561
285331
|
await saveThreadSession(persisted.threadSession);
|
|
@@ -284565,6 +285335,7 @@ async function hydrateCliThreadState(threadId) {
|
|
|
284565
285335
|
async function persistInteractiveCliState(state) {
|
|
284566
285336
|
await persistCliThreadState({
|
|
284567
285337
|
threadId: state.threadId,
|
|
285338
|
+
threadScopeKey: state.threadScopeKey,
|
|
284568
285339
|
recentMessages: state.recentMessages,
|
|
284569
285340
|
contextSnapshot: state.contextSnapshot
|
|
284570
285341
|
});
|
|
@@ -284580,13 +285351,13 @@ async function persistCliThreadState(input) {
|
|
|
284580
285351
|
threadSession,
|
|
284581
285352
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
284582
285353
|
};
|
|
284583
|
-
const filePath = cliThreadStatePath(input.threadId);
|
|
285354
|
+
const filePath = cliThreadStatePath(input.threadId, input.threadScopeKey);
|
|
284584
285355
|
await fs14.promises.mkdir(path14.dirname(filePath), { recursive: true, mode: 448 });
|
|
284585
285356
|
await fs14.promises.writeFile(filePath, JSON.stringify(payload, null, 2), { mode: 384 });
|
|
284586
285357
|
}
|
|
284587
|
-
async function readCliThreadState(threadId) {
|
|
285358
|
+
async function readCliThreadState(threadId, threadScopeKey) {
|
|
284588
285359
|
try {
|
|
284589
|
-
const raw = await fs14.promises.readFile(cliThreadStatePath(threadId), "utf8");
|
|
285360
|
+
const raw = await fs14.promises.readFile(cliThreadStatePath(threadId, threadScopeKey), "utf8");
|
|
284590
285361
|
const parsed = JSON.parse(raw);
|
|
284591
285362
|
if (parsed.version !== 1 || parsed.threadId !== threadId) return null;
|
|
284592
285363
|
return {
|
|
@@ -284601,12 +285372,28 @@ async function readCliThreadState(threadId) {
|
|
|
284601
285372
|
return null;
|
|
284602
285373
|
}
|
|
284603
285374
|
}
|
|
284604
|
-
async function deleteCliThreadState(threadId) {
|
|
284605
|
-
await fs14.promises.rm(cliThreadStatePath(threadId), { force: true }).catch(() => void 0);
|
|
285375
|
+
async function deleteCliThreadState(threadId, threadScopeKey) {
|
|
285376
|
+
await fs14.promises.rm(cliThreadStatePath(threadId, threadScopeKey), { force: true }).catch(() => void 0);
|
|
284606
285377
|
}
|
|
284607
|
-
function cliThreadStatePath(threadId) {
|
|
285378
|
+
function cliThreadStatePath(threadId, threadScopeKey) {
|
|
284608
285379
|
const base = process.env.PERCH_CLI_STATE_DIR?.trim() || path14.join(os5.homedir(), ".perch", "threads");
|
|
284609
|
-
return path14.join(base, `${safeCliThreadId(threadId)}.json`);
|
|
285380
|
+
return path14.join(base, safeCliThreadScopeKey(threadScopeKey), `${safeCliThreadId(threadId)}.json`);
|
|
285381
|
+
}
|
|
285382
|
+
async function resolveCliThreadScopeKey(connection) {
|
|
285383
|
+
const session = await readStoredCliAuthSession().catch(() => null);
|
|
285384
|
+
const sessionUsable = isStoredCliAuthSessionUsable(session);
|
|
285385
|
+
const authenticated = Boolean(connection?.authenticated || sessionUsable);
|
|
285386
|
+
const appUrl = connection?.appUrl ?? session?.appUrl ?? "local";
|
|
285387
|
+
const userId = connection?.userId ?? session?.userId ?? null;
|
|
285388
|
+
const email = connection?.email ?? session?.email ?? null;
|
|
285389
|
+
const fallbackToken = authenticated && !userId && !email ? session?.accessToken ?? null : null;
|
|
285390
|
+
const authKey = authenticated ? `user:${userId ?? ""}|email:${email ?? ""}|token:${fallbackToken ? createHash4("sha256").update(fallbackToken).digest("hex").slice(0, 20) : ""}` : "anonymous";
|
|
285391
|
+
const raw = `app:${appUrl}|${authKey}`;
|
|
285392
|
+
const prefix = authenticated ? "user" : "anon";
|
|
285393
|
+
return `${prefix}-${createHash4("sha256").update(raw).digest("hex").slice(0, 20)}`;
|
|
285394
|
+
}
|
|
285395
|
+
function safeCliThreadScopeKey(threadScopeKey) {
|
|
285396
|
+
return (threadScopeKey?.trim() || "anon-local").replace(/[^a-zA-Z0-9_.-]+/g, "_").slice(0, 96);
|
|
284610
285397
|
}
|
|
284611
285398
|
function safeCliThreadId(threadId) {
|
|
284612
285399
|
return threadId.trim().replace(/[^a-zA-Z0-9_.-]+/g, "_").slice(0, 96) || "cli-default";
|
|
@@ -285480,6 +286267,7 @@ var init_perch_cli = __esm({
|
|
|
285480
286267
|
init_learningMemory();
|
|
285481
286268
|
init_toolDefinitions();
|
|
285482
286269
|
init_nodeLocalBridge();
|
|
286270
|
+
init_agentSkillRegistry();
|
|
285483
286271
|
execFileAsync3 = promisify3(execFile3);
|
|
285484
286272
|
DEFAULT_CLI_LOGIN_APP_URL = "https://app.perchai.app";
|
|
285485
286273
|
CLI_PACKAGE_VERSION = readCliPackageVersion();
|
|
@@ -285513,6 +286301,7 @@ Usage:
|
|
|
285513
286301
|
perch login
|
|
285514
286302
|
perch status
|
|
285515
286303
|
perch logout
|
|
286304
|
+
perch skills [name]
|
|
285516
286305
|
perch run "<task>" [--json] [--thread <id>] [--cwd <dir>] [--mode ask|agents|plan] [--persona saffron|quill]
|
|
285517
286306
|
perch ap evidence <folder> [--json] [--out <dir>] [--timestamp <id>]
|
|
285518
286307
|
perch ap packet <folder> [--json] [--out <dir>] [--timestamp <id>]
|
|
@@ -285523,6 +286312,7 @@ Commands:
|
|
|
285523
286312
|
login Open browser sign-in and save this terminal's Perch session.
|
|
285524
286313
|
status Show the saved CLI auth/app connection status.
|
|
285525
286314
|
logout Clear the saved CLI auth session.
|
|
286315
|
+
skills List Perch core skills, or show one skill body.
|
|
285526
286316
|
run Run a natural-language Perch turn through the shared runtime.
|
|
285527
286317
|
ap evidence Prepare AP evidence, cases, metrics, and graph artifacts.
|
|
285528
286318
|
ap packet Generate the full AP audit packet and report artifacts.
|
|
@@ -285532,6 +286322,7 @@ Commands:
|
|
|
285532
286322
|
While Perch is working: type steering text and press Enter; Ctrl-C stops; Ctrl-E expands details.
|
|
285533
286323
|
/help Show this list.
|
|
285534
286324
|
/status Show cwd, auth, mode, persona, permission, and thread.
|
|
286325
|
+
/skills [name] List Perch core skills, or show one skill body.
|
|
285535
286326
|
/cwd [dir] Show or change the working directory.
|
|
285536
286327
|
/permission [mode] Show or set default, auto_review, take_the_wheel, or plan.
|
|
285537
286328
|
/permissions [mode] Alias for /permission.
|
|
@@ -285582,6 +286373,7 @@ Commands:
|
|
|
285582
286373
|
];
|
|
285583
286374
|
PERCH_SPLASH_COMMANDS = [
|
|
285584
286375
|
["/status", "show auth, route, tools, and thread"],
|
|
286376
|
+
["/skills", "show reusable operator skills"],
|
|
285585
286377
|
["/persona", "swap saffron or quill"],
|
|
285586
286378
|
["/permission", "change autonomy for the next turns"],
|
|
285587
286379
|
["/login", "connect your Perch account"]
|