gentle-pi 2.5.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +139 -30
- package/assets/agents/gentle-ai-worker.md +4 -0
- package/assets/agents/jd-fix-agent.md +18 -0
- package/assets/agents/jd-judge-a.md +1 -1
- package/assets/agents/jd-judge-b.md +1 -1
- package/assets/agents/sdd-apply.md +7 -5
- package/assets/agents/sdd-archive.md +5 -3
- package/assets/agents/sdd-design.md +4 -0
- package/assets/agents/sdd-explore.md +4 -0
- package/assets/agents/sdd-init.md +4 -0
- package/assets/agents/sdd-onboard.md +4 -0
- package/assets/agents/sdd-proposal.md +4 -0
- package/assets/agents/sdd-remediate.md +37 -0
- package/assets/agents/sdd-research.md +26 -3
- package/assets/agents/sdd-spec.md +4 -0
- package/assets/agents/sdd-status.md +9 -75
- package/assets/agents/sdd-sync.md +4 -0
- package/assets/agents/sdd-tasks.md +4 -0
- package/assets/agents/sdd-verify.md +5 -3
- package/assets/chains/sdd-full.chain.md +4 -0
- package/assets/chains/sdd-plan.chain.md +4 -0
- package/assets/chains/sdd-verify.chain.md +4 -0
- package/assets/migrations/managed-assets-v2.5.0.json +7 -0
- package/assets/orchestrator-delegation.md +21 -3
- package/assets/sdd-orchestrator-workflow.md +54 -21
- package/assets/support/sdd-status-contract.md +34 -90
- package/contracts/telemetry/runtime-aggregate-v1.schema.json +67 -0
- package/docs/telemetry.md +57 -1
- package/docs/windows-startup-console-visibility.md +18 -0
- package/extensions/ask-user-choice.ts +143 -15
- package/extensions/codegraph-tools.ts +1 -0
- package/extensions/gentle-agents.ts +795 -50
- package/extensions/gentle-ai.ts +2033 -322
- package/extensions/gentle-shell.ts +145 -42
- package/extensions/gentle-todo.ts +47 -12
- package/extensions/quiet-tools.ts +1 -0
- package/extensions/runtime-metrics.ts +121 -0
- package/extensions/sdd-init.ts +2 -2
- package/extensions/startup-banner.ts +52 -75
- package/lib/agent-profiles.ts +550 -0
- package/lib/agents-completion-delivery.ts +72 -0
- package/lib/agents-config.ts +7 -10
- package/lib/agents-history.ts +9 -1
- package/lib/agents-messaging.ts +187 -0
- package/lib/agents-protocol.ts +77 -5
- package/lib/agents-runner.ts +548 -26
- package/lib/agents-thread-view.ts +57 -0
- package/lib/agents-view-layout.ts +40 -0
- package/lib/agents-view.ts +548 -191
- package/lib/agents-widget.ts +33 -14
- package/lib/gentle-ai-binary.ts +3 -1
- package/lib/gentle-ai-renderer.ts +8 -6
- package/lib/native-review-cli.ts +288 -1
- package/lib/orchestrator-presence.ts +337 -0
- package/lib/profiles-orchestrator.ts +203 -0
- package/lib/review-candidate-view-owner.ts +296 -46
- package/lib/review-candidate-view.ts +30 -20
- package/lib/review-consent-component.ts +247 -0
- package/lib/review-consent-ui.ts +53 -8
- package/lib/review-host-relay.ts +28 -0
- package/lib/review-integration-v2.ts +187 -5
- package/lib/review-last-event-controller.ts +7 -4
- package/lib/review-reminder-receipt.ts +74 -0
- package/lib/review-session-standing-permission.ts +27 -6
- package/lib/runtime-metrics-children.ts +197 -0
- package/lib/runtime-metrics-delivery.ts +68 -0
- package/lib/runtime-metrics-native.ts +174 -0
- package/lib/runtime-metrics-policy.ts +51 -0
- package/lib/runtime-metrics.ts +308 -0
- package/lib/sdd-preflight.ts +362 -81
- package/lib/sdd-research-capabilities.ts +228 -0
- package/lib/sdd-status.ts +29 -7
- package/lib/session-worktree-registry.ts +118 -0
- package/lib/shell-bar.ts +47 -1
- package/lib/shell-card.ts +1 -4
- package/lib/shell-changes-view.ts +362 -37
- package/lib/shell-changes.ts +81 -1
- package/lib/shell-prompt.ts +11 -15
- package/lib/shell-sidebar-banner.ts +11 -0
- package/lib/shell-sidebar-layout.ts +213 -0
- package/lib/shell-sidebar.ts +41 -0
- package/lib/shell-todo.ts +28 -11
- package/lib/telemetry-trigger.ts +2 -0
- package/package.json +6 -3
- package/runtime/gentle-ai-binary.mjs +3 -1
- package/runtime/native-review-cli.mjs +288 -1
- package/runtime/review-integration-v2.mjs +187 -5
- package/runtime/telemetry-trigger.mjs +2 -0
- package/scripts/build-runtime-modules.mjs +9 -1
- package/scripts/check-types.mjs +125 -0
- package/scripts/gentle-ai-installer.mjs +10 -10
- package/scripts/install-gentle-ai.mjs +12 -0
- package/scripts/install-tui-mode-setting.mjs +114 -0
- package/scripts/test-packed-runner.mjs +16 -2
- package/scripts/types-baseline.json +95 -0
- package/scripts/verify-package-files.mjs +4 -2
- package/skills/_shared/review-ledger-contract.md +17 -1
- package/skills/issue-creation/SKILL.md +3 -3
- package/skills/judgment-day/SKILL.md +17 -3
- package/skills/judgment-day/references/prompts-and-formats.md +14 -3
- package/tests/agent-profiles.test.ts +722 -0
- package/tests/agents-completion-delivery.test.ts +94 -0
- package/tests/agents-config.test.ts +62 -0
- package/tests/agents-fake-child.ts +15 -1
- package/tests/agents-grouping.test.ts +179 -0
- package/tests/agents-integration.test.ts +100 -0
- package/tests/agents-messaging.test.ts +94 -0
- package/tests/agents-protocol.test.ts +45 -0
- package/tests/agents-queries.test.ts +190 -0
- package/tests/agents-responsive.test.ts +43 -0
- package/tests/agents-runner.test.ts +571 -14
- package/tests/agents-thread-view.test.ts +45 -0
- package/tests/agents-view.test.ts +476 -65
- package/tests/agents-widget.test.ts +31 -1
- package/tests/artifact-language.test.ts +25 -2
- package/tests/ask-user-choice.test.ts +169 -3
- package/tests/asset-installation-runtime.test.ts +108 -0
- package/tests/autonomous-guard.test.ts +116 -1
- package/tests/codegraph-tools.test.ts +2 -1
- package/tests/delegated-key-learnings-contract.test.ts +1 -1
- package/tests/devbinary/native-review-parity.devtest.ts +2 -0
- package/tests/feature-request-form.test.ts +67 -0
- package/tests/fixtures/agents-messaging-child.mjs +5 -0
- package/tests/fixtures/runtime-metrics-native-batches.json +6 -0
- package/tests/gentle-agents.test.ts +1454 -33
- package/tests/gentle-ai-binary.test.ts +7 -2
- package/tests/gentle-ai-installer.test.ts +47 -47
- package/tests/gentle-ai-renderer.test.ts +38 -0
- package/tests/gentle-ai.test.ts +944 -4
- package/tests/gentle-shell.test.ts +303 -12
- package/tests/gentle-todo.test.ts +54 -10
- package/tests/install-tui-mode-setting.test.ts +324 -0
- package/tests/issue-creation-skill.test.ts +22 -0
- package/tests/model-routing-authority.test.ts +12 -0
- package/tests/native-review-capability-contract.test.ts +23 -1
- package/tests/native-review-cli.test.ts +277 -3
- package/tests/native-review-parity.test.ts +14 -7
- package/tests/native-sdd-attempt-authority.test.ts +7 -2
- package/tests/orchestrator-presence.test.ts +389 -0
- package/tests/package-manifest.test.ts +232 -7
- package/tests/profiles-orchestrator.test.ts +208 -0
- package/tests/quiet-tool-rendering.test.ts +1 -0
- package/tests/rdd-aware-verification-contract.test.ts +10 -0
- package/tests/review-agent-end-preflight.test.ts +332 -24
- package/tests/review-candidate-view.test.ts +304 -6
- package/tests/review-consent-ui.test.ts +352 -0
- package/tests/review-contract-prompt.test.ts +14 -0
- package/tests/review-controller-native-routing.test.ts +563 -3
- package/tests/review-controller.test.ts +1 -1
- package/tests/review-host-relay-restart-parity.test.ts +142 -1
- package/tests/review-host-relay-routing.test.ts +364 -4
- package/tests/review-host-relay.test.ts +29 -0
- package/tests/review-integration-v2-forward.test.ts +44 -0
- package/tests/review-integration-v2.test.ts +164 -0
- package/tests/review-last-event-closure.test.ts +105 -1
- package/tests/review-ledger-contract.test.ts +61 -6
- package/tests/review-reminder-receipt.test.ts +62 -0
- package/tests/review-session-standing-permission-controller.test.ts +52 -4
- package/tests/review-session-standing-permission.test.ts +30 -0
- package/tests/runtime-harness.mjs +447 -39
- package/tests/runtime-metrics-children.test.ts +207 -0
- package/tests/runtime-metrics-delivery.test.ts +85 -0
- package/tests/runtime-metrics-extension.test.ts +196 -0
- package/tests/runtime-metrics-model.test.ts +76 -0
- package/tests/runtime-metrics-native.test.ts +275 -0
- package/tests/runtime-metrics-policy.test.ts +62 -0
- package/tests/runtime-metrics.test.ts +187 -0
- package/tests/sdd-agent-tools.test.ts +10 -1
- package/tests/sdd-execution-routing-contract.test.ts +28 -0
- package/tests/sdd-managed-runtime-settlement.test.ts +331 -0
- package/tests/sdd-native-managed-uptake.test.ts +253 -0
- package/tests/sdd-planning-routing-contract.test.ts +45 -0
- package/tests/sdd-preflight.test.ts +252 -8
- package/tests/sdd-research-capabilities.test.ts +256 -0
- package/tests/sdd-research-live.test.ts +241 -0
- package/tests/sdd-selection-transport.test.ts +504 -0
- package/tests/sdd-status.test.ts +51 -0
- package/tests/session-worktree-registry.test.ts +135 -0
- package/tests/shell-card.test.ts +24 -3
- package/tests/shell-changes-view.test.ts +471 -8
- package/tests/shell-changes.test.ts +168 -0
- package/tests/shell-prompt.test.ts +28 -6
- package/tests/shell-sidebar-banner.test.ts +23 -0
- package/tests/shell-sidebar-layout.test.ts +387 -0
- package/tests/shell-sidebar.test.ts +50 -0
- package/tests/shell-todo.test.ts +100 -11
- package/tests/startup-banner.test.ts +126 -0
- package/tests/telemetry-trigger.test.ts +3 -1
|
@@ -15,94 +15,43 @@ Any phase that selects, continues, applies, verifies, syncs, or archives an SDD
|
|
|
15
15
|
|
|
16
16
|
## Native Engine
|
|
17
17
|
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
- `gentle-ai sdd-status --contract gentle-ai.sdd-status/v2` is the sole status authority for every store. It is read-only: inspect its native projection unchanged and never launch a phase, prepare consent, or grant roots while reading it.
|
|
19
|
+
- If native status is unavailable, malformed, or does not select the requested change/workspace, stop and report that failure. Do not construct a local status, infer readiness from artifacts, substitute continuation, or bypass it through Engram.
|
|
20
|
+
- `nextRecommended`, `dependencies`, `blockedReasons`, `actionContext`, and optional `phaseInstructions` are producer facts. Route only by their typed values, never by prose or a local lifecycle graph. A genuine blocker's human-readable explanation belongs in `blockedReasons`; a non-blocking diagnostic belongs in `notes`; neither belongs in `nextRecommended`.
|
|
21
|
+
- Runtime-attempt authority is separate from status: runtime-bearing work uses the provider `sdd-attempt acquire|settle` flow and its `proceed`, `blocked`, or `complete` result.
|
|
22
|
+
- Only an explicitly authorized `gentle-ai sdd-continue` may prepare a missing change-instance marker. `ensureChangeInstanceMarker` has no status caller; its sole production path is `PrepareChangeInstanceConsent` through `sdd-continue`.
|
|
23
|
+
|
|
24
|
+
## Bounded Planning Routing
|
|
25
|
+
|
|
26
|
+
For authoritative native status, route only by the bounded `nextRecommended` token and dependency states; never infer a route from prose. Keep genuine blockers in `blockedReasons` and non-blocking diagnostics in `notes`, never in `nextRecommended`, and report them without discarding them to enable a route.
|
|
27
|
+
|
|
28
|
+
| `nextRecommended` | Planning route |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `propose` | `sdd-proposal` |
|
|
31
|
+
| `spec` | `sdd-spec` |
|
|
32
|
+
| `design` | `sdd-design` |
|
|
33
|
+
| `tasks` | `sdd-tasks` |
|
|
34
|
+
|
|
35
|
+
Native unprefixed tokens are the only automatic planning routes. Prefixed or locally derived status tokens never authorize a phase.
|
|
36
|
+
|
|
37
|
+
These planning routes remain runnable when missing planning artifacts leave `dependencies.apply: blocked`; do not require apply readiness to produce those artifacts. This is a planning-only exception, not permission to run apply or another blocked non-planning phase.
|
|
38
|
+
|
|
39
|
+
Before any planning launch, stop for ambiguous change selection, unresolved session preflight, or unsafe action context. Carry `actionContext` and prove planned writes are within the authoritative workspace or allowed edit roots; workspace-planning without allowed edit roots remains read-only. Planning does not bypass the init guard, pre-proposal gate, or phase approval requirements.
|
|
40
|
+
|
|
41
|
+
## Bounded Execution Routing
|
|
42
|
+
|
|
43
|
+
| Native `nextRecommended` | Pi executor |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `apply` | `sdd-apply` |
|
|
46
|
+
| `verify` | `sdd-verify` |
|
|
47
|
+
| `remediate` | `sdd-remediate` |
|
|
48
|
+
| `archive` | `sdd-archive` |
|
|
49
|
+
|
|
50
|
+
Execute only a native selected action whose dependency and `actionContext` permit it. Unknown, malformed, blocked, or unsupported actions stop before work; no local route, prefixed token, or prose can replace them. `notes` is separate from `blockedReasons` and never gates: report a non-empty `notes` value as informational and proceed when the dependency and `blockedReasons` gates allow. Manual `sdd-sync` remains its intentional local resolver and is never an automatic native-status dispatch.
|
|
25
51
|
|
|
26
52
|
## Status Schema
|
|
27
53
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```yaml
|
|
31
|
-
schemaName: spec-driven
|
|
32
|
-
changeName: <change-name>
|
|
33
|
-
artifactStore: openspec | engram | both | none
|
|
34
|
-
planningHome:
|
|
35
|
-
root: <project-or-openspec-root>
|
|
36
|
-
changesDir: <openspec/changes or memory topic prefix>
|
|
37
|
-
changeRoot: <openspec/changes/<change> or memory topic prefix>
|
|
38
|
-
artifactPaths:
|
|
39
|
-
proposal: [<path-or-topic>]
|
|
40
|
-
specs: [<path-or-topic>]
|
|
41
|
-
design: [<path-or-topic>]
|
|
42
|
-
tasks: [<path-or-topic>]
|
|
43
|
-
applyProgress: [<path-or-topic>]
|
|
44
|
-
verifyReport: [<path-or-topic>]
|
|
45
|
-
syncReport: [<path-or-topic>]
|
|
46
|
-
contextFiles:
|
|
47
|
-
proposal: [<concrete readable files/topics>]
|
|
48
|
-
specs: [<concrete readable files/topics>]
|
|
49
|
-
design: [<concrete readable files/topics>]
|
|
50
|
-
tasks: [<concrete readable files/topics>]
|
|
51
|
-
applyProgress: [<concrete readable files/topics>]
|
|
52
|
-
verifyReport: [<concrete readable files/topics>]
|
|
53
|
-
syncReport: [<concrete readable files/topics>]
|
|
54
|
-
artifacts:
|
|
55
|
-
proposal: missing | done | partial
|
|
56
|
-
specs: missing | done | partial
|
|
57
|
-
design: missing | done | partial
|
|
58
|
-
tasks: missing | done | partial
|
|
59
|
-
applyProgress: missing | done | partial
|
|
60
|
-
verifyReport: missing | done | partial
|
|
61
|
-
syncReport: missing | done | partial
|
|
62
|
-
taskProgress: # implementation-owned plus malformed unresolved rows
|
|
63
|
-
total: 0
|
|
64
|
-
complete: 0
|
|
65
|
-
remaining: 0
|
|
66
|
-
unchecked: []
|
|
67
|
-
deferredParentActions:
|
|
68
|
-
total: 0
|
|
69
|
-
complete: 0
|
|
70
|
-
remaining: 0
|
|
71
|
-
unchecked: []
|
|
72
|
-
taskArtifactErrors: []
|
|
73
|
-
applyState: blocked | all_done | ready | not_applicable
|
|
74
|
-
dependencies:
|
|
75
|
-
apply: blocked | ready | all_done | not_applicable
|
|
76
|
-
verify: blocked | ready | all_done | not_applicable
|
|
77
|
-
sync: blocked | ready | all_done | not_applicable
|
|
78
|
-
archive: blocked | ready | all_done | not_applicable
|
|
79
|
-
actionContext:
|
|
80
|
-
mode: repo-local | workspace-planning
|
|
81
|
-
workspaceRoot: <absolute path>
|
|
82
|
-
allowedEditRoots: [<absolute paths>]
|
|
83
|
-
warnings: []
|
|
84
|
-
nextRecommended: <bounded-machine-token>
|
|
85
|
-
isNonAuthoritative: false # boolean; true when the native engine is not authoritative for the store
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Task Ownership
|
|
89
|
-
|
|
90
|
-
New task checkboxes end with the terminal marker `<!-- sdd-owner: implementation -->`. An unmarked legacy checkbox is implementation-owned. Supported legacy non-implementation rows are informational only. Any line containing `sdd-owner` that is unsupported, duplicated, or non-terminal is malformed: add its exact line to `taskArtifactErrors` and `blockedReasons`, and count it as unresolved implementation work even when checked. `taskProgress` reports implementation work.
|
|
91
|
-
|
|
92
|
-
## Apply State
|
|
93
|
-
|
|
94
|
-
- `blocked`: required apply artifacts are missing, task selection is ambiguous, malformed ownership markers exist, or action context makes edits unsafe.
|
|
95
|
-
- `all_done`: tasks artifact exists and every implementation task is checked `[x]`.
|
|
96
|
-
- `ready`: tasks artifact exists, at least one implementation task remains unchecked, and edit scope is safe.
|
|
97
|
-
- `not_applicable`: emitted for non-authoritative stores (see Engine Authority by Store). This is NOT a blocker.
|
|
98
|
-
|
|
99
|
-
## Dependency States
|
|
100
|
-
|
|
101
|
-
- `apply` is `ready` only when specs, design, and tasks are available and task progress is not all done.
|
|
102
|
-
- `verify` is ready after implementation completion when tasks are complete or apply-progress exists. RDD authority and receipts never gate the apply -> verify -> sync -> archive route. Unchecked implementation tasks remain CRITICAL blockers for full archive readiness.
|
|
103
|
-
- `sync` is `ready` only when verify-report exists and has no unresolved `FAIL`, `BLOCKED`, `CRITICAL`, or verification blockers. `engram`/`none` modes may mark sync `not_applicable`.
|
|
104
|
-
- `archive` is `ready` only when verify-report exists, sync is complete or not applicable, and implementation tasks are complete. CRITICAL verification issues have no override. Explicit recorded exceptions are limited to non-critical partial archives or stale-checkbox reconciliation when apply-progress/verify-report prove completion.
|
|
105
|
-
- `not_applicable`: emitted for non-authoritative stores (engram, none, and both when no `openspec/` directory exists) when `nextRecommended: "resolve-via-engram"` is active. `not_applicable` is NOT a gate failure — readiness must be resolved from Engram instead of from these fields.
|
|
54
|
+
Consume the native v2 projection (`schemaName: gentle-ai.sdd-status`, `schemaVersion: 2`) losslessly. Its producer-defined selection, artifact locators, task progress, seven dependencies, `actionContext`, `blockedReasons`, optional execution instructions, remediation state, and `nextRecommended` are status facts, not a Pi schema to recreate.
|
|
106
55
|
|
|
107
56
|
## Action Context Guard
|
|
108
57
|
|
|
@@ -112,11 +61,6 @@ The orchestrator MUST carry `actionContext` into any phase launch.
|
|
|
112
61
|
- If `allowedEditRoots` is present, only edit or move files within those roots.
|
|
113
62
|
- If a phase cannot prove a file is inside the authoritative workspace or allowed edit roots, stop and ask for clarification.
|
|
114
63
|
|
|
115
|
-
## Engine Authority by Store
|
|
116
|
-
|
|
117
|
-
- `openspec` and `both` (when `openspec/` directory exists): the local SDD status engine resolves artifact state from disk and is authoritative. Phase executors must obey it.
|
|
118
|
-
- `engram`, `none`, and `both` (when `openspec/` directory does NOT exist): the local engine cannot read Engram artifacts. It returns `nextRecommended: "resolve-via-engram"` and empty `blockedReasons`. This output is **non-authoritative**. The orchestrator must resolve readiness directly from Engram using the Engram memory tools injected by the memory provider on the change topic keys (`sdd/{change-name}/proposal`, `sdd/{change-name}/spec`, etc.) instead of relying on the engine's dependency states. The `artifactStore` field still reflects the real chosen store value (e.g. `"both"`) and must not be rewritten.
|
|
119
|
-
|
|
120
64
|
## Native Runtime Attempt Authority
|
|
121
65
|
|
|
122
66
|
The compact SDD runtime attempt authority is separate from artifact dispatch and status. It is artifact-store agnostic: the same acquire/settle discipline applies to `openspec`, `engram`, `both`, and `none` stores. Its payload MUST NOT be embedded in the SDD v1 status schema above; status reports artifact state only, never attempt tokens or attempt counters. No OpenSpec or Engram attempt ledger may be created or mirrored by Pi.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "gentle-ai.telemetry-runtime-aggregate/v1",
|
|
4
|
+
"description": "Sanitized stdin for gentle-ai telemetry runtime send --json. Maximum UTF-8 input 16384 bytes. One best-effort send attempt, no client persistence or retry. Rows are independent observations, not a session composition. No caller identity is accepted.",
|
|
5
|
+
"type": "object", "additionalProperties": false,
|
|
6
|
+
"required": ["schema", "registry", "host", "rows"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema": {"const": "gentle-ai.telemetry-runtime-aggregate/v1"},
|
|
9
|
+
"registry": {"const": 1},
|
|
10
|
+
"host": {"enum": ["claude-code", "opencode", "codex", "pi"]},
|
|
11
|
+
"rows": {"type": "array", "minItems": 1, "maxItems": 32, "items": {"$ref": "#/$defs/row"}}
|
|
12
|
+
},
|
|
13
|
+
"$defs": {
|
|
14
|
+
"metric": {"oneOf": [{"type": "integer", "minimum": 0, "maximum": 999999999999}, {"type": "null"}, {"const": "unsupported"}]},
|
|
15
|
+
"count": {"type": "integer", "minimum": 0, "maximum": 999999999999},
|
|
16
|
+
"token": {
|
|
17
|
+
"type": "object", "additionalProperties": false,
|
|
18
|
+
"required": ["reported", "unavailable", "unsupported", "sum"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"reported": {"$ref": "#/$defs/count"}, "unavailable": {"$ref": "#/$defs/count"},
|
|
21
|
+
"unsupported": {"$ref": "#/$defs/count"}, "sum": {"$ref": "#/$defs/count"}
|
|
22
|
+
},
|
|
23
|
+
"if": {"properties": {"reported": {"const": 0}}},
|
|
24
|
+
"then": {"properties": {"sum": {"const": 0}}}
|
|
25
|
+
},
|
|
26
|
+
"duration": {
|
|
27
|
+
"type": "object", "additionalProperties": false, "required": ["kind", "measured_count", "sum_ms"],
|
|
28
|
+
"properties": {"kind": {}, "measured_count": {}, "sum_ms": {}},
|
|
29
|
+
"oneOf": [
|
|
30
|
+
{"properties": {"kind": {"const": "unavailable"}, "measured_count": {"const": 0}, "sum_ms": {"type": "null"}}},
|
|
31
|
+
{"properties": {"kind": {"enum": ["request", "message"]}, "measured_count": {"type": "integer", "minimum": 1, "maximum": 999999999999}, "sum_ms": {"type": "number", "minimum": 0, "maximum": 999999999999}}}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
"effort": {"enum": ["off", "minimal", "low", "medium", "high", "xhigh", "max", "not_selected", "unknown", "custom", "unavailable", "unsupported"]},
|
|
35
|
+
"model": {
|
|
36
|
+
"type": "object", "additionalProperties": false, "required": ["provider", "id"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"provider": {"type": "string", "maxLength": 32},
|
|
39
|
+
"id": {"type": "string", "maxLength": 64}
|
|
40
|
+
},
|
|
41
|
+
"anyOf": [
|
|
42
|
+
{"properties": {"provider": {"pattern": "^[a-z0-9][a-z0-9-]{0,31}$"}, "id": {"pattern": "^(claude|gpt|o[1-9]|codex|gemini|gemma|deepseek|glm|qwen|qwq|kimi|moonshot|llama|codellama|mistral|mixtral|codestral|devstral|magistral|ministral|minimax|grok|phi|nemotron|jamba|hunyuan|doubao|ernie|mimo|granite|olmo|smollm|starcoder|titan)[a-z0-9]*([-_.:][a-z0-9]+){0,8}$"}}},
|
|
43
|
+
{"properties": {"provider": {"const": "unknown"}, "id": {"const": "unknown"}}},
|
|
44
|
+
{"properties": {"provider": {"const": "custom"}, "id": {"const": "custom"}}},
|
|
45
|
+
{"properties": {"provider": {"const": "opencode"}, "id": {"const": "custom"}}}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"row": {
|
|
49
|
+
"type": "object", "additionalProperties": false,
|
|
50
|
+
"required": ["model", "model_evidence", "agent_kind", "agent_class", "selected_effort", "effective_effort", "launches", "responses", "input_tokens", "output_tokens", "cache_read_tokens", "cache_creation_tokens", "reasoning_tokens", "total_tokens", "error_category", "duration"],
|
|
51
|
+
"properties": {
|
|
52
|
+
"reasoning_tokens": {"$ref": "#/$defs/token"},
|
|
53
|
+
"total_tokens": {"$ref": "#/$defs/token"},
|
|
54
|
+
"agent_class": {"enum": ["orchestrator", "worker", "explore", "verify", "unknown", "sdd-init", "sdd-explore", "sdd-research", "sdd-propose", "sdd-spec", "sdd-design", "sdd-tasks", "sdd-apply", "sdd-verify", "sdd-archive", "sdd-onboard", "sdd-status", "sdd-sync", "jd-judge-a", "jd-judge-b", "jd-fix-agent", "review-risk", "review-readability", "review-reliability", "review-resilience", "review-refuter", "review-validator"]},
|
|
55
|
+
"error_category": {"enum": ["none", "unknown", "auth", "output_length", "aborted", "api", "rate_limit", "server"]},
|
|
56
|
+
"duration": {"$ref": "#/$defs/duration"},
|
|
57
|
+
"model": {"$ref": "#/$defs/model"},
|
|
58
|
+
"model_evidence": {"enum": ["selected", "response", "unknown"]},
|
|
59
|
+
"agent_kind": {"enum": ["orchestrator", "built_in", "custom", "unknown"]},
|
|
60
|
+
"selected_effort": {"$ref": "#/$defs/effort"}, "effective_effort": {"$ref": "#/$defs/effort"},
|
|
61
|
+
"launches": {"$ref": "#/$defs/metric", "description": "Source-observed event count only; null when not observed. Never reconstructed from sessions."}, "responses": {"$ref": "#/$defs/metric", "description": "Source-observed response occurrence count, independent of token coverage and success."},
|
|
62
|
+
"input_tokens": {"$ref": "#/$defs/token"}, "output_tokens": {"$ref": "#/$defs/token"},
|
|
63
|
+
"cache_read_tokens": {"$ref": "#/$defs/token"}, "cache_creation_tokens": {"$ref": "#/$defs/token"}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
package/docs/telemetry.md
CHANGED
|
@@ -1,6 +1,62 @@
|
|
|
1
1
|
# Telemetry
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Runtime usage telemetry is best effort: an available usage event gets at most one
|
|
4
|
+
asynchronous attempt through `gentle-ai telemetry runtime send --json`. Busy,
|
|
5
|
+
failed, disabled, or cancelled attempts are discarded silently. There is no
|
|
6
|
+
metrics disk storage, outbox, retry, backoff, cooldown, daemon, or session reconstruction.
|
|
7
|
+
|
|
8
|
+
The production encoder uses the byte-identical [native schema mirror](../contracts/telemetry/runtime-aggregate-v1.schema.json).
|
|
9
|
+
[The synthetic fixture](../tests/fixtures/runtime-metrics-native-batches.json) pins its
|
|
10
|
+
SHA-256 and exact one-shot stdin bytes. No old intake fallback is used. These are
|
|
11
|
+
fake-subprocess tests, not a live collector or deployment verification.
|
|
12
|
+
|
|
13
|
+
## Runtime usage flow
|
|
14
|
+
|
|
15
|
+
1. A finalized primary assistant message or child completion supplies available usage.
|
|
16
|
+
Child-host extensions do not independently consume primary usage.
|
|
17
|
+
2. Pi builds event-local sanitized rows, not cumulative session totals. An occupied
|
|
18
|
+
attempt slot discards the event; it never queues it for later.
|
|
19
|
+
3. One cancellable immediate defers binary verification and subprocess launch beyond
|
|
20
|
+
the provider callback. The native command owns fresh policy and exactly one POST.
|
|
21
|
+
4. Only `stored`, `duplicate`, `discarded`, or `disabled` results are recognized.
|
|
22
|
+
All are terminal. `stored` and `duplicate` reflect collector acknowledgement,
|
|
23
|
+
not client persistence; Pi retains nothing and never retries.
|
|
24
|
+
|
|
25
|
+
There is no policy or capability subprocess before send, and no ingest or flush call.
|
|
26
|
+
The packaged binary is verified; development overrides are refused for runtime usage.
|
|
27
|
+
Missing binaries and unsupported commands discard without installation or fallback.
|
|
28
|
+
|
|
29
|
+
Replacement and shutdown cancel an unstarted attempt or request termination of its
|
|
30
|
+
child immediately, without a wait loop or final send. The process slot remains busy
|
|
31
|
+
until actual close, preventing overlap even if a cancelled process is slow to exit.
|
|
32
|
+
A one-second process timeout requests termination; it is not a retry timer or a hard
|
|
33
|
+
bound on synchronous binary verification or event-loop stalls.
|
|
34
|
+
|
|
35
|
+
## Data and source limits
|
|
36
|
+
|
|
37
|
+
Wire fields are the schema/registry, host, public model with evidence, available
|
|
38
|
+
selected/effective effort, orchestrator or known built-in subagent class, source
|
|
39
|
+
launch/response occurrence coverage, six token coverages, explicitly reported typed
|
|
40
|
+
duration, and a sanitized error category. Occurrences never represent sessions.
|
|
41
|
+
Prompts, responses, code, paths, private names, source IDs, and raw errors never enter
|
|
42
|
+
the payload. There is no `batch_id`; native creates the remote `delivery_id`.
|
|
43
|
+
|
|
44
|
+
One event produces 1–32 rows within 16 KiB. Oversized or invalid events discard
|
|
45
|
+
whole rather than splitting into multiple sends. Child launch selection is a separate
|
|
46
|
+
row with zero response-token coverage, never substituted for per-response evidence.
|
|
47
|
+
|
|
48
|
+
- Token coverage distinguishes reported, unavailable, and unsupported values. Pi's
|
|
49
|
+
SDK-positive counters are usable; zero defaults and absence do not prove reported zero.
|
|
50
|
+
- Selected model/effort is captured at the request hook, separately from response
|
|
51
|
+
model and effective-effort evidence. Ambiguous request sequences discard selection.
|
|
52
|
+
- Pi hooks do not correlate requests/retries reliably, so this adapter does not infer duration.
|
|
53
|
+
- Child configuration classification uses packaged built-in definitions, not agent names.
|
|
54
|
+
Launch configuration is not proof of the model or selected effort of each child response.
|
|
55
|
+
- Bounded live child observations remain in RAM until completion. No completed child
|
|
56
|
+
event is retained for forwarding. A completion without usage creates no usage send.
|
|
57
|
+
- Primary object deduplication uses weak tombstones; copied objects are distinct.
|
|
58
|
+
Child completion tombstones are capped at 256 per extension session. Source IDs
|
|
59
|
+
stay local and are never exported. No session history is read or reconstructed.
|
|
4
60
|
|
|
5
61
|
## What Gentle Pi does
|
|
6
62
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Windows Startup Console Capture
|
|
2
|
+
|
|
3
|
+
Use this protocol to validate the startup Git child processes on a real Windows desktop. Linux CI can verify spawn configuration but cannot observe Windows console windows.
|
|
4
|
+
|
|
5
|
+
## Capture
|
|
6
|
+
|
|
7
|
+
1. Start a Windows window-event trace before launching Pi. Capture `EVENT_OBJECT_SHOW`, its timestamp, HWND, owner PID, and owner session.
|
|
8
|
+
2. Deliberately launch a known visible, short-lived console as a positive control. If its show event is absent, the capture is **INCONCLUSIVE**.
|
|
9
|
+
3. Build or install the candidate Gentle Pi package and start `pi` from a repository whose path contains spaces. Leave it idle for at least 10 seconds so the startup identity lookups (`git rev-parse --show-toplevel` and `git rev-parse --git-common-dir`), branch lookup, initial shell scan, and repeated poll run.
|
|
10
|
+
4. Correlate each show event with `GetWindowThreadProcessId`, then use its timestamp, host PID/session, and Procmon process-creation ancestry and command line to associate it with a Pi-launched Git invocation. The HWND can be owned by `conhost.exe`, OpenConsole, or Windows Terminal rather than `git.exe`.
|
|
11
|
+
|
|
12
|
+
## Expected Result
|
|
13
|
+
|
|
14
|
+
No `WS_VISIBLE` show event is associated with the Git invocation for the startup identity lookups, banner branch lookup, initial shell scan, or repeated shell polling. A visible show event proves window visibility, not that it was unobscured on screen. Process start alone is not visible-window evidence. If event-to-invocation association cannot be established, report **INCONCLUSIVE**, not pass.
|
|
15
|
+
|
|
16
|
+
## Scope
|
|
17
|
+
|
|
18
|
+
This protocol does not cover user-configured external editors. Their inherited-stdio launch is intentional and may open a visible window.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { DynamicBorder } from "@earendil-works/pi-coding-agent";
|
|
3
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
3
|
+
import { Container, Input, isKeyRelease, matchesKey, Text, type KeybindingsManager, type TuiMouseEvent } from "@earendil-works/pi-tui";
|
|
4
4
|
import { type Static, Type } from "typebox";
|
|
5
5
|
import { NativeChoiceList } from "../lib/native-choice-list.ts";
|
|
6
6
|
import { createNativeFullscreenInteraction } from "../lib/native-fullscreen-interaction.ts";
|
|
@@ -25,6 +25,9 @@ const ChoiceParamsSchema = Type.Object(
|
|
|
25
25
|
maxItems: 4,
|
|
26
26
|
description: "Two to four ordered closed options",
|
|
27
27
|
}),
|
|
28
|
+
allowCustomResponse: Type.Optional(Type.Boolean({
|
|
29
|
+
description: "Opt in to an Other… free-text response. Never enable for provider-owned consent prompts, maintenance authorizations, or any exact opaque-token decision.",
|
|
30
|
+
})),
|
|
28
31
|
},
|
|
29
32
|
{ additionalProperties: false },
|
|
30
33
|
);
|
|
@@ -42,9 +45,108 @@ interface ChoiceDetails {
|
|
|
42
45
|
question: string;
|
|
43
46
|
options: ChoiceOption[];
|
|
44
47
|
selection?: ChoiceSelection;
|
|
48
|
+
customResponse?: string;
|
|
45
49
|
cancelled?: true;
|
|
46
50
|
}
|
|
47
51
|
|
|
52
|
+
type ChoiceResult = ChoiceSelection | { customResponse: string };
|
|
53
|
+
|
|
54
|
+
class CustomResponseEditor extends Container {
|
|
55
|
+
private readonly input = new Input({ prompt: "> ", placeholder: "Type your response" });
|
|
56
|
+
private readonly validationText = new Text("", 1, 0);
|
|
57
|
+
private readonly keybindings: KeybindingsManager | undefined;
|
|
58
|
+
private readonly onSubmit: (value: string) => void;
|
|
59
|
+
private readonly onCancel: () => void;
|
|
60
|
+
|
|
61
|
+
constructor(
|
|
62
|
+
keybindings: KeybindingsManager | undefined,
|
|
63
|
+
onSubmit: (value: string) => void,
|
|
64
|
+
onCancel: () => void,
|
|
65
|
+
) {
|
|
66
|
+
super();
|
|
67
|
+
this.keybindings = keybindings;
|
|
68
|
+
this.onSubmit = onSubmit;
|
|
69
|
+
this.onCancel = onCancel;
|
|
70
|
+
this.input.focused = true;
|
|
71
|
+
this.addChild(new Text("Custom response", 1, 0));
|
|
72
|
+
this.addChild(this.input);
|
|
73
|
+
this.addChild(this.validationText);
|
|
74
|
+
this.addChild(new Text("Submit to continue • Cancel to return to choices", 1, 0));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
handleInput(data: string): void {
|
|
78
|
+
if (isKeyRelease(data)) return;
|
|
79
|
+
if (this.matches(data, "tui.select.cancel")) {
|
|
80
|
+
this.onCancel();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (this.matches(data, "tui.input.submit")) {
|
|
84
|
+
const value = this.input.getValue();
|
|
85
|
+
if (value.trim().length > 0) this.onSubmit(value);
|
|
86
|
+
else this.validationText.setText("Response cannot be empty.");
|
|
87
|
+
this.invalidate();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (this.matches(data, "tui.editor.deleteCharBackward")) {
|
|
91
|
+
this.input.handleInput(data);
|
|
92
|
+
this.validationText.setText("");
|
|
93
|
+
this.invalidate();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.input.handleInput(data);
|
|
97
|
+
this.validationText.setText("");
|
|
98
|
+
this.invalidate();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private matches(
|
|
102
|
+
data: string,
|
|
103
|
+
binding: "tui.select.cancel" | "tui.input.submit" | "tui.editor.deleteCharBackward",
|
|
104
|
+
): boolean {
|
|
105
|
+
if (this.keybindings?.matches) return this.keybindings.matches(data, binding);
|
|
106
|
+
const key = binding === "tui.select.cancel" ? "escape"
|
|
107
|
+
: binding === "tui.input.submit" ? "enter" : "backspace";
|
|
108
|
+
return matchesKey(data, key);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
class ChoiceModeView extends Container {
|
|
113
|
+
private editing = false;
|
|
114
|
+
private readonly list: NativeChoiceList<{ id: string; label: string; description: string }>;
|
|
115
|
+
private readonly editor: CustomResponseEditor;
|
|
116
|
+
|
|
117
|
+
constructor(
|
|
118
|
+
list: NativeChoiceList<{ id: string; label: string; description: string }>,
|
|
119
|
+
editor: CustomResponseEditor,
|
|
120
|
+
) {
|
|
121
|
+
super();
|
|
122
|
+
this.list = list;
|
|
123
|
+
this.editor = editor;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
showEditor(): void {
|
|
127
|
+
this.editing = true;
|
|
128
|
+
this.invalidate();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
showList(): void {
|
|
132
|
+
this.editing = false;
|
|
133
|
+
this.invalidate();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
handleInput(data: string): void {
|
|
137
|
+
if (this.editing) this.editor.handleInput(data);
|
|
138
|
+
else this.list.handleInput(data);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
override handleMouse(event: TuiMouseEvent) {
|
|
142
|
+
return this.editing ? undefined : this.list.handleMouse(event);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override render(width: number): string[] {
|
|
146
|
+
return (this.editing ? this.editor : this.list).render(width);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
48
150
|
function reconcileToolAvailability(pi: ExtensionAPI, interactiveTui: boolean): void {
|
|
49
151
|
const active = pi.getActiveTools();
|
|
50
152
|
const isActive = active.includes(CHOICE_TOOL_NAME);
|
|
@@ -62,10 +164,12 @@ function resultDetails(params: ChoiceParams): ChoiceDetails {
|
|
|
62
164
|
export default function askUserChoice(pi: ExtensionAPI): void {
|
|
63
165
|
pi.registerTool({
|
|
64
166
|
name: CHOICE_TOOL_NAME,
|
|
167
|
+
renderShell: "self",
|
|
65
168
|
label: "Ask User Choice",
|
|
66
|
-
description: "Ask one
|
|
169
|
+
description: "Ask one single-select question with two to four ordered options. A custom response is available only when allowCustomResponse is explicitly enabled.",
|
|
67
170
|
promptGuidelines: [
|
|
68
|
-
"Use ask_user_choice only for one exactly representable
|
|
171
|
+
"Use ask_user_choice only for one exactly representable single-select question with 2-4 ordered options. Enable allowCustomResponse only when free text is safe and intended.",
|
|
172
|
+
"Never enable allowCustomResponse for provider-owned consent prompts, maintenance authorizations, or any decision that requires an exact opaque token.",
|
|
69
173
|
],
|
|
70
174
|
parameters: ChoiceParamsSchema,
|
|
71
175
|
executionMode: "sequential",
|
|
@@ -79,37 +183,54 @@ export default function askUserChoice(pi: ExtensionAPI): void {
|
|
|
79
183
|
label: option.label,
|
|
80
184
|
description: option.description,
|
|
81
185
|
}));
|
|
82
|
-
|
|
186
|
+
const customItemId = "choice-custom-response";
|
|
187
|
+
if (params.allowCustomResponse === true) {
|
|
188
|
+
items.push({ id: customItemId, label: "Other…", description: "Provide a custom response" });
|
|
189
|
+
}
|
|
190
|
+
let selection: ChoiceResult | undefined;
|
|
83
191
|
try {
|
|
84
192
|
pi.events.emit(ASK_USER_CHOICE_BLOCKED_EVENT, { active: true });
|
|
85
|
-
selection = await ctx.ui.custom<
|
|
193
|
+
selection = await ctx.ui.custom<ChoiceResult | undefined>((tui, theme, keybindings, done) => {
|
|
86
194
|
const list = new NativeChoiceList(items, {
|
|
87
195
|
selectedPrefix: (text) => theme.fg("accent", text),
|
|
88
196
|
selectedText: (text) => theme.fg("accent", text),
|
|
89
197
|
description: (text) => theme.fg("muted", text),
|
|
90
198
|
hoverBackground: (text) => theme.bg("toolPendingBg", text),
|
|
91
199
|
}, keybindings);
|
|
92
|
-
const container = createNativeFullscreenInteraction({
|
|
93
|
-
keyboardTarget: list,
|
|
94
|
-
requestRender: () => tui.requestRender(),
|
|
95
|
-
mouseObserver: list.createMouseObserver(() => tui.requestRender()),
|
|
96
|
-
});
|
|
97
200
|
let completed = false;
|
|
98
|
-
const finish = (result:
|
|
201
|
+
const finish = (result: ChoiceResult | undefined) => {
|
|
99
202
|
if (completed) return;
|
|
100
203
|
completed = true;
|
|
101
204
|
list.setDisabled(true);
|
|
102
205
|
done(result);
|
|
103
206
|
};
|
|
207
|
+
let view: ChoiceModeView;
|
|
208
|
+
const editor = new CustomResponseEditor(
|
|
209
|
+
keybindings,
|
|
210
|
+
(value) => finish({ customResponse: value }),
|
|
211
|
+
() => view.showList(),
|
|
212
|
+
);
|
|
213
|
+
view = new ChoiceModeView(list, editor);
|
|
214
|
+
const container = createNativeFullscreenInteraction({
|
|
215
|
+
keyboardTarget: view,
|
|
216
|
+
requestRender: () => tui.requestRender(),
|
|
217
|
+
mouseObserver: list.createMouseObserver(() => tui.requestRender()),
|
|
218
|
+
});
|
|
104
219
|
list.onSelect = (item) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
220
|
+
if (item.id === customItemId) {
|
|
221
|
+
view.showEditor();
|
|
222
|
+
tui.requestRender();
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const index = items.indexOf(item);
|
|
226
|
+
const option = params.options[index];
|
|
227
|
+
if (option) finish({ value: option.value, label: option.label, index: index + 1 });
|
|
228
|
+
}
|
|
108
229
|
};
|
|
109
230
|
list.onCancel = () => finish(undefined);
|
|
110
231
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
111
232
|
container.addChild(new Text(theme.fg("accent", theme.bold(params.question)), 1, 0));
|
|
112
|
-
container.addChild(
|
|
233
|
+
container.addChild(view);
|
|
113
234
|
container.addChild(new Text(theme.fg("dim", "↑↓ navigate • Enter select • Esc cancel"), 1, 0));
|
|
114
235
|
container.addChild(new DynamicBorder((text: string) => theme.fg("accent", text)));
|
|
115
236
|
return container;
|
|
@@ -124,6 +245,12 @@ export default function askUserChoice(pi: ExtensionAPI): void {
|
|
|
124
245
|
details: { ...resultDetails(params), cancelled: true },
|
|
125
246
|
};
|
|
126
247
|
}
|
|
248
|
+
if ("customResponse" in selection) {
|
|
249
|
+
return {
|
|
250
|
+
content: [{ type: "text", text: `User responded: ${selection.customResponse}` }],
|
|
251
|
+
details: { ...resultDetails(params), customResponse: selection.customResponse },
|
|
252
|
+
};
|
|
253
|
+
}
|
|
127
254
|
return {
|
|
128
255
|
content: [{ type: "text", text: `User selected: ${selection.index}. ${selection.label} (value: ${selection.value})` }],
|
|
129
256
|
details: { ...resultDetails(params), selection },
|
|
@@ -147,6 +274,7 @@ export default function askUserChoice(pi: ExtensionAPI): void {
|
|
|
147
274
|
if (details?.selection) {
|
|
148
275
|
return new Text(theme.fg("success", `✓ ${details.selection.index}. ${details.selection.label}`), 0, 0);
|
|
149
276
|
}
|
|
277
|
+
if (details?.customResponse !== undefined) return new Text(theme.fg("success", "✓ Custom response"), 0, 0);
|
|
150
278
|
return new Text(theme.fg("warning", "Cancelled"), 0, 0);
|
|
151
279
|
},
|
|
152
280
|
});
|
|
@@ -278,6 +278,7 @@ const runCodeGraphCommand: CodeGraphRunner = async (args, options) => {
|
|
|
278
278
|
export function createCodeGraphTool(runner: CodeGraphRunner = runCodeGraphCommand) {
|
|
279
279
|
return {
|
|
280
280
|
name: "codegraph",
|
|
281
|
+
renderShell: "self" as const,
|
|
281
282
|
label: "CodeGraph",
|
|
282
283
|
description:
|
|
283
284
|
"Initialize, search, or explore the CodeGraph index for the current Pi workspace only. This tool never accepts a project path or shell command.",
|