@agentwhy/cli 0.0.0-dev → 0.2.0
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/LICENSE +1 -1
- package/README.md +57 -5
- package/dist/adapter/claude-code/contract/assumptions.js +16 -4
- package/dist/adapter/claude-code/contract/denials.js +16 -1
- package/dist/adapter/claude-code/contract/desktop-sessions.js +28 -0
- package/dist/adapter/claude-code/contract/entry-points.js +6 -1
- package/dist/adapter/claude-code/contract/fields.js +2 -0
- package/dist/adapter/claude-code/contract/hooks.js +8 -0
- package/dist/adapter/claude-code/contract/identifiers.js +2 -0
- package/dist/adapter/claude-code/contract/layout.js +2 -0
- package/dist/adapter/claude-code/contract/line-types.js +2 -0
- package/dist/adapter/claude-code/contract/projects.js +2 -0
- package/dist/adapter/claude-code/contract/recognition.js +2 -0
- package/dist/adapter/claude-code/contract/settings.js +2 -0
- package/dist/adapter/claude-code/contract/task-notifications.js +2 -0
- package/dist/adapter/claude-code/contract/version.js +14 -1
- package/dist/adapter/claude-code/discovery/claude-code-project-catalogue.js +12 -12
- package/dist/adapter/claude-code/discovery/claude-code-recognition.js +2 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-catalogue.js +28 -7
- package/dist/adapter/claude-code/discovery/claude-code-session-discovery.js +2 -0
- package/dist/adapter/claude-code/discovery/claude-code-session-titles.js +30 -6
- package/dist/adapter/claude-code/discovery/claude-desktop-titles.js +102 -0
- package/dist/adapter/claude-code/discovery/session-entries.js +2 -0
- package/dist/adapter/claude-code/events/delegation-index.js +2 -0
- package/dist/adapter/claude-code/events/transcript-scan.js +6 -5
- package/dist/adapter/claude-code/hooks/hook-output.js +2 -0
- package/dist/adapter/claude-code/hooks/pre-tool-use-input.js +2 -0
- package/dist/adapter/claude-code/hooks/stop-input.js +2 -0
- package/dist/adapter/claude-code/hooks/subagent-stop-input.js +4 -0
- package/dist/adapter/claude-code/probe/claude-code-probe.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/agent-tool-input-key-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/denial-kind-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/denied-call-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/identifier-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/line-type-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/sidechain-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/task-notification-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/tool-result-reference-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/tool-use-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/tool-version-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/top-level-key-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/unknown-line-type-key-collector.js +2 -0
- package/dist/adapter/claude-code/probe/collectors/working-directory-collector.js +2 -0
- package/dist/adapter/claude-code/probe/meta-tally.js +2 -0
- package/dist/adapter/claude-code/probe/transcript-line.js +2 -0
- package/dist/adapter/claude-code/probe/transcript-tally.js +2 -0
- package/dist/adapter/claude-code/settings/deny-entries.js +2 -0
- package/dist/adapter/claude-code/settings/hook-entries.js +9 -0
- package/dist/adapter/claude-code/settings/refuse-project.js +99 -0
- package/dist/adapter/codex/contract/actions.js +2 -0
- package/dist/adapter/codex/contract/assumptions.js +2 -0
- package/dist/adapter/codex/contract/chat-folders.js +19 -0
- package/dist/adapter/codex/contract/delegations.js +2 -0
- package/dist/adapter/codex/contract/deliveries.js +2 -0
- package/dist/adapter/codex/contract/envelope.js +2 -0
- package/dist/adapter/codex/contract/hook-refusals.js +2 -0
- package/dist/adapter/codex/contract/hooks.js +51 -1
- package/dist/adapter/codex/contract/messages.js +2 -0
- package/dist/adapter/codex/contract/permissions.js +2 -0
- package/dist/adapter/codex/contract/reviews.js +2 -0
- package/dist/adapter/codex/contract/session.js +29 -1
- package/dist/adapter/codex/contract/turns.js +2 -0
- package/dist/adapter/codex/contract/version.js +2 -0
- package/dist/adapter/codex/discovery/codex-on-this-computer.js +13 -0
- package/dist/adapter/codex/discovery/codex-project-catalogue.js +2 -12
- package/dist/adapter/codex/discovery/codex-session-catalogue.js +2 -1
- package/dist/adapter/codex/discovery/codex-session-discovery.js +2 -0
- package/dist/adapter/codex/discovery/session-owners.js +2 -0
- package/dist/adapter/codex/events/action-items.js +2 -0
- package/dist/adapter/codex/events/codex-session-source.js +2 -0
- package/dist/adapter/codex/events/hook-refusals.js +2 -0
- package/dist/adapter/codex/events/rollout-scan.js +1 -1
- package/dist/adapter/codex/hooks/codex-conversation.js +54 -0
- package/dist/adapter/codex/hooks/pre-tool-use-input.js +2 -0
- package/dist/adapter/codex/hooks/reader.js +38 -0
- package/dist/adapter/codex/hooks/stop-input.js +32 -0
- package/dist/adapter/codex/hooks/stop-refusals.js +3 -6
- package/dist/adapter/codex/probe/codex-probe.js +2 -0
- package/dist/adapter/codex/settings/codex-check.js +38 -0
- package/dist/adapter/codex/settings/codex-hooks.js +168 -1
- package/dist/adapter/codex/settings/hook-approval.js +374 -0
- package/dist/cli/commands/check-cli-command.js +2 -0
- package/dist/cli/commands/codex-stop-cli-command.js +15 -12
- package/dist/cli/commands/doctor-arguments.js +2 -0
- package/dist/cli/commands/doctor-usage.js +2 -0
- package/dist/cli/commands/init-cli-command.js +10 -5
- package/dist/cli/commands/notify-cli-command.js +3 -1
- package/dist/cli/commands/refuse-cli-command.js +9 -4
- package/dist/cli/commands/report-arguments.js +2 -0
- package/dist/cli/commands/report-usage.js +2 -0
- package/dist/cli/commands/sessions-cli-command.js +9 -1
- package/dist/cli/commands/start-cli-command.js +29 -2
- package/dist/cli/commands/watch-cli-command.js +4 -2
- package/dist/cli/exit-codes.js +2 -0
- package/dist/cli.js +10 -0
- package/dist/composition-root.js +80 -15
- package/dist/core/access/command-line.js +48 -2
- package/dist/core/access/listing.js +2 -0
- package/dist/core/access/path-tokens.js +2 -0
- package/dist/core/access/protected-access.js +36 -3
- package/dist/core/access/protected-values.js +17 -0
- package/dist/core/access/search-output.js +2 -0
- package/dist/core/access/search-reach.js +2 -0
- package/dist/core/combined-project-catalogue.js +7 -1
- package/dist/core/correlation/correlate.js +13 -1
- package/dist/core/detector/prompt-signals.js +2 -0
- package/dist/core/guarded-places.js +42 -0
- package/dist/core/nearest-project.js +5 -2
- package/dist/core/policy/glob.js +2 -0
- package/dist/core/policy/parse-policy.js +2 -0
- package/dist/core/policy/policy.js +14 -2
- package/dist/core/policy/resolve-policy.js +2 -0
- package/dist/core/redaction/entropy.js +2 -0
- package/dist/core/redaction/redactor.js +2 -0
- package/dist/core/redaction/value-shapes.js +2 -0
- package/dist/core/redaction/value-trace.js +2 -0
- package/dist/core/session-catalogue.js +7 -0
- package/dist/core/session-filter.js +2 -0
- package/dist/infrastructure/clack-asker.js +2 -0
- package/dist/infrastructure/clack-chooser.js +2 -0
- package/dist/infrastructure/clack-multi-chooser.js +2 -0
- package/dist/infrastructure/file-alert-store.js +10 -3
- package/dist/infrastructure/file-checked-store.js +2 -0
- package/dist/infrastructure/file-mark-store.js +2 -0
- package/dist/infrastructure/file-onboarding-store.js +2 -0
- package/dist/infrastructure/file-page-servers.js +51 -0
- package/dist/infrastructure/folder-window.js +2 -0
- package/dist/infrastructure/node-agentwhy-invocation.js +2 -0
- package/dist/infrastructure/node-background-run.js +45 -0
- package/dist/infrastructure/node-browser.js +2 -0
- package/dist/infrastructure/node-file-system.js +42 -1
- package/dist/infrastructure/node-local-server.js +2 -0
- package/dist/infrastructure/node-page-probe.js +40 -0
- package/dist/infrastructure/os-notifier.js +2 -0
- package/dist/infrastructure/real-directory.js +2 -0
- package/dist/infrastructure/shell-command-trial.js +60 -0
- package/dist/infrastructure/terminal-banner.js +2 -0
- package/dist/ports/command-trial.js +1 -0
- package/dist/ports/directory-reader.js +14 -1
- package/dist/ports/file-replacer.js +1 -0
- package/dist/ports/mark-store.js +2 -0
- package/dist/ports/page-server.js +1 -0
- package/dist/refuse/command-reach.js +2 -0
- package/dist/refuse/command-refusal.js +19 -30
- package/dist/refuse/render/refusal-words.js +3 -1
- package/dist/report/build-report.js +59 -11
- package/dist/report/check/actions-digest.js +3 -0
- package/dist/report/check/check-lines.js +2 -1
- package/dist/report/check/render/text-digest-renderer.js +31 -9
- package/dist/report/check/session-actions.js +4 -6
- package/dist/report/check/session-check.js +8 -0
- package/dist/report/choose-policy.js +7 -1
- package/dist/report/nothing-saved-here.js +16 -0
- package/dist/report/private-files/tell-lists.js +2 -0
- package/dist/report/project-rules.js +2 -0
- package/dist/report/refusals.js +15 -0
- package/dist/report/render/home-relative.js +2 -0
- package/dist/report/render/html-head.js +2 -0
- package/dist/report/render/html-report-styles.js +2 -0
- package/dist/report/render/html-sidebar.js +2 -0
- package/dist/report/render/path-tail.js +2 -0
- package/dist/report/render/report-copy.js +2 -0
- package/dist/report/render/report-page/advanced-view.js +2 -0
- package/dist/report/render/report-page/files-view.js +2 -0
- package/dist/report/render/report-page/files.js +2 -0
- package/dist/report/render/report-page/fix-wizard-script.js +2 -0
- package/dist/report/render/report-page/helpers-view.js +2 -0
- package/dist/report/render/report-page/item-names.js +2 -0
- package/dist/report/render/report-page/protect-patterns.js +2 -0
- package/dist/report/render/report-page/report-views.js +2 -0
- package/dist/report/render/report-page/to-do-view.js +3 -2
- package/dist/report/render/text-report-renderer.js +2 -0
- package/dist/report/render/ui/add-file-popup.js +2 -0
- package/dist/report/render/ui/app-sidebar.js +2 -0
- package/dist/report/render/ui/ask-panel.js +2 -0
- package/dist/report/render/ui/avatar.js +2 -0
- package/dist/report/render/ui/backdrop.js +2 -0
- package/dist/report/render/ui/brand-mark.js +2 -0
- package/dist/report/render/ui/checklist.js +2 -0
- package/dist/report/render/ui/confirm-dialog.js +2 -0
- package/dist/report/render/ui/drawer.js +2 -0
- package/dist/report/render/ui/file-chip.js +2 -0
- package/dist/report/render/ui/fold-line.js +2 -0
- package/dist/report/render/ui/guide-card.js +2 -0
- package/dist/report/render/ui/live-script.js +2 -0
- package/dist/report/render/ui/page-shell.js +2 -0
- package/dist/report/render/ui/popup.js +2 -0
- package/dist/report/render/ui/progress.js +2 -0
- package/dist/report/render/ui/project-list.js +9 -9
- package/dist/report/render/ui/stats.js +2 -0
- package/dist/report/render/ui/status-icon.js +2 -0
- package/dist/report/render/ui/status-look.js +2 -0
- package/dist/report/render/ui/task-list.js +2 -0
- package/dist/report/render/ui/tokens.js +2 -0
- package/dist/report/render/ui/update-notice.js +2 -0
- package/dist/report/render/ui/words/app-words.js +3 -3
- package/dist/report/render/ui/words/onboarding-words.js +9 -9
- package/dist/report/render/ui/words/projects-words.js +3 -3
- package/dist/report/render/ui/words/report-words.js +11 -11
- package/dist/report/render/ui/words/settings-words.js +30 -6
- package/dist/report/rule-names.js +2 -0
- package/dist/report/session-report.js +2 -0
- package/dist/report/start/conversations/calendar-view.js +2 -0
- package/dist/report/start/conversations/conversation-columns.js +2 -0
- package/dist/report/start/conversations/empty-week.js +2 -0
- package/dist/report/start/conversations/files-window.js +2 -0
- package/dist/report/start/conversations/period-section.js +2 -0
- package/dist/report/start/conversations/periods-script.js +2 -0
- package/dist/report/start/conversations/periods.js +2 -0
- package/dist/report/start/conversations/week-view.js +2 -0
- package/dist/report/start/conversations/weeks.js +2 -0
- package/dist/report/start/detached-start.js +75 -0
- package/dist/report/start/month/month-view.js +2 -0
- package/dist/report/start/onboarding/done.js +9 -3
- package/dist/report/start/onboarding/finish-onboarding.js +6 -4
- package/dist/report/start/onboarding/intro.js +2 -0
- package/dist/report/start/onboarding/onboarding-renderer.js +4 -4
- package/dist/report/start/onboarding/onboarding-script.js +2 -0
- package/dist/report/start/onboarding/onboarding-view.js +1 -1
- package/dist/report/start/onboarding/project-step.js +1 -1
- package/dist/report/start/onboarding/steps.js +2 -0
- package/dist/report/start/onboarding/welcome.js +2 -0
- package/dist/report/start/page-notice.js +2 -0
- package/dist/report/start/projects/index-projects.js +5 -2
- package/dist/report/start/projects/moved-page.js +2 -0
- package/dist/report/start/projects/project-switch.js +2 -0
- package/dist/report/start/projects/projects-window.js +2 -0
- package/dist/report/start/projects/temporary-space.js +2 -0
- package/dist/report/start/render/start-words.js +15 -1
- package/dist/report/start/repository.js +2 -0
- package/dist/report/start/serve/index-handler.js +4 -1
- package/dist/report/start/serve/settings-setup.js +10 -0
- package/dist/report/start/session-start.js +69 -29
- package/dist/report/start/settings/alerts-tab.js +4 -1
- package/dist/report/start/settings/files-tab.js +18 -12
- package/dist/report/start/settings/general-tab.js +33 -1
- package/dist/report/start/settings/settings-renderer.js +2 -0
- package/dist/report/start/settings/settings-script.js +8 -1
- package/dist/report/start/settings/settings-view.js +29 -2
- package/dist/report/start/settings/settings-windows.js +16 -5
- package/dist/report/start/settings-files.js +2 -0
- package/dist/report/start/to-fix/done-list.js +2 -0
- package/dist/report/start/to-fix/file-window.js +2 -0
- package/dist/report/start/to-fix/to-fix-list.js +2 -0
- package/dist/report/start/to-fix/to-fix-renderer.js +2 -0
- package/dist/report/start/to-fix/to-fix-script.js +2 -0
- package/dist/report/watch/agent-alert.js +3 -0
- package/dist/report/watch/codex-turn-format.js +69 -0
- package/dist/report/watch/notice-choices.js +2 -0
- package/dist/report/watch/notice-settings.js +2 -0
- package/dist/report/watch/preferences.js +2 -0
- package/dist/report/watch/render/codex-request-words.js +106 -0
- package/dist/report/watch/render/instruction-words.js +114 -12
- package/dist/report/watch/render/notice-words.js +74 -4
- package/dist/report/watch/subagent-watch.js +270 -45
- package/dist/setup/behind.js +2 -0
- package/dist/setup/codex-mirror.js +311 -104
- package/dist/setup/not-a-project.js +2 -0
- package/dist/setup/project-setup.js +2 -0
- package/dist/shared/compare.js +2 -0
- package/dist/shared/content-version.js +2 -0
- package/dist/shared/counter.js +2 -0
- package/dist/shared/file-stamp.js +2 -0
- package/dist/shared/label.js +2 -0
- package/dist/shared/package-name.js +2 -0
- package/dist/shared/plain-invocation.js +2 -0
- package/dist/shared/printable.js +2 -0
- package/dist/shared/sentence.js +2 -0
- package/dist/shared/terminal-logo.js +2 -0
- package/dist/shared/text-table.js +2 -0
- package/dist/shared/wrap.js +2 -0
- package/package.json +2 -1
- package/dist/refuse/render/codex-stop-words.js +0 -21
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
5
|
import { pill, trashButton } from '../../render/ui/button.js';
|
|
@@ -91,13 +93,17 @@ function ruleRow(row, at, view) {
|
|
|
91
93
|
const action = row.remove !== undefined && canWrite ? remove(removeWindowId(at))
|
|
92
94
|
: row.untell !== undefined ? remove(untellWindowId(at))
|
|
93
95
|
: '<span class="set-none" aria-hidden="true">—</span>';
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
+
const covered = row.covered;
|
|
97
|
+
const gapped = row.kept !== undefined || covered !== undefined;
|
|
98
|
+
const icon = !row.watched ? '' : gapped ? OPEN_LOCK_SVG : MODE_SVG[row.mode];
|
|
99
|
+
const iconClass = !row.watched ? '' : ' set-icon-' + (gapped ? 'gap' : row.mode);
|
|
96
100
|
return '<li class="set-rule' + (row.watched ? '' : ' set-rule-off') + (watchable ? ' set-rule-watchable' : '') + '"' + (watchable ? ' data-set-row' : '') + '>' +
|
|
97
101
|
'<span class="set-icon' + iconClass + '" aria-hidden="true">' + icon + '</span>' +
|
|
98
102
|
'<span class="set-rule-text"><span class="set-rule-name">' + label + '</span>' +
|
|
99
103
|
'<span class="chip set-rule-chip" title="' + e(pattern) + '">' + e(patternShort(pattern)) + '</span>' +
|
|
100
|
-
(row.kept === undefined ? '' : '<span class="set-rule-gap">' + inLanguages((t) => t('set.rule.gap.' + row.kept)) + '</span>') +
|
|
104
|
+
(row.kept === undefined ? '' : '<span class="set-rule-gap">' + inLanguages((t) => t('set.rule.gap.' + row.kept)) + '</span>') +
|
|
105
|
+
// SW19: tracked here, and still refused by Claude Code's own rule for a wider pattern - said on the row, like a half block.
|
|
106
|
+
(covered === undefined ? '' : '<span class="set-rule-gap">' + inLanguages((t) => t('set.rule.covered', { pattern: e(patternShort(covered)) })) + '</span>') + '</span>' +
|
|
101
107
|
'<span class="set-rule-mode">' + mode + '</span>' +
|
|
102
108
|
'<span class="set-rule-src">' + tag(inLanguages((t) => t('set.src.short.' + row.source)), SOURCE_TONE[row.source]) + '</span>' +
|
|
103
109
|
'<span class="set-rule-act">' + action + '</span>' +
|
|
@@ -149,21 +155,21 @@ function finishCard(view) {
|
|
|
149
155
|
});
|
|
150
156
|
}
|
|
151
157
|
/**
|
|
152
|
-
* `codex-
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
158
|
+
* `codex-approves-its-own-hook` AO3, AO10: in a project that uses Codex, whether the files blocked here are kept from
|
|
159
|
+
* Codex too. Verified (`on`), a grey line states the fact: from the first message, in the terminal and in VS Code,
|
|
160
|
+
* nothing to confirm in Codex. Written but not verified (`stale`), a coral line says Codex may still ask, with the one
|
|
161
|
+
* write that makes it automatic. Not written (`off`) and Claude Code's block running, a coral line with the same
|
|
162
|
+
* write; where Claude Code's block does not run either, Finish blocking above writes both, and this says nothing.
|
|
156
163
|
*/
|
|
157
164
|
function codexCard(view) {
|
|
158
|
-
if (!view.known || view.codex === undefined)
|
|
165
|
+
if (!view.known || view.codex === undefined || !view.stop.on)
|
|
159
166
|
return '';
|
|
160
167
|
if (view.codex === 'on')
|
|
161
168
|
return callout({ tone: 'grey', body: inLanguages((t) => t('set.codex.on')) });
|
|
162
|
-
|
|
163
|
-
return '';
|
|
169
|
+
const stale = view.codex === 'stale';
|
|
164
170
|
return callout({
|
|
165
171
|
tone: 'coral',
|
|
166
|
-
body: inLanguages((t) => t('set.codex.off')),
|
|
167
|
-
...(view.canWrite ? { action: pill({ label: inLanguages((t) => t('set.codex.go')), tone: 'primary', size: 'task', href: '#' + CODEX_WINDOW, attributes: opener(CODEX_WINDOW) }) } : {}),
|
|
172
|
+
body: inLanguages((t) => t(stale ? 'set.codex.stale' : 'set.codex.off')),
|
|
173
|
+
...(view.canWrite ? { action: pill({ label: inLanguages((t) => t(stale ? 'set.codex.fix' : 'set.codex.go')), tone: 'primary', size: 'task', href: '#' + CODEX_WINDOW, attributes: opener(CODEX_WINDOW) }) } : {}),
|
|
168
174
|
});
|
|
169
175
|
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
4
|
+
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
2
5
|
import { avatar } from '../../render/ui/avatar.js';
|
|
3
6
|
import { BRAND_MARK } from '../../render/ui/brand-mark.js';
|
|
4
7
|
import { pill, TRASH_SVG } from '../../render/ui/button.js';
|
|
5
8
|
import { callout } from '../../render/ui/callout.js';
|
|
6
9
|
import { opener } from '../../render/ui/popup.js';
|
|
10
|
+
import { toggleSwitch } from '../../render/ui/switch.js';
|
|
7
11
|
import { tag } from '../../render/ui/tag.js';
|
|
12
|
+
import { stateLine } from './alerts-tab.js';
|
|
8
13
|
import { scopeWindowId, UNINSTALL_WINDOW } from './settings-windows.js';
|
|
9
14
|
/**
|
|
10
15
|
* General (`for-people-who-build-with-ai.md` F56, asked for 2026-09-24; redrawn 2026-09-25): who what agentwhy saved in
|
|
@@ -25,9 +30,36 @@ export function generalTab(view, welcome) {
|
|
|
25
30
|
// which-project V5: which AI agentwhy sees, in the words the project step and the list of projects say it.
|
|
26
31
|
'<p class="set-quiet set-general-note"><span class="set-info" aria-hidden="true">i</span><span>' + inLanguages((t) => t('proj.which')) + '</span></p>' +
|
|
27
32
|
'</section>' +
|
|
33
|
+
systemCard(view) +
|
|
28
34
|
setupCard(welcome) +
|
|
29
35
|
uninstallCard(view);
|
|
30
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Whether agentwhy also shows what it says in the corner of the screen (`2026-10-02-said-where-the-person-is.md` SW13).
|
|
39
|
+
* Asked for by the maintainer on 2026-10-02, who found the notifications tiresome and had only a command to turn them
|
|
40
|
+
* off. Written at once, as Alerts' optional rows are (R26a), keeping every other channel in force; on a page opened as a
|
|
41
|
+
* file, the script offers the command to copy instead.
|
|
42
|
+
*/
|
|
43
|
+
function systemCard(view) {
|
|
44
|
+
const on = view.system.on;
|
|
45
|
+
const others = view.system.channels.filter((channel) => channel !== 'os');
|
|
46
|
+
const next = on ? (others.length === 0 ? ['chat'] : others) : [...others, 'os'];
|
|
47
|
+
return '<section class="set-box set-system"><div class="set-head"><h2 class="set-h2">' + inLanguages((t) => t('set.system.title')) + '</h2>' +
|
|
48
|
+
'<p class="set-lead">' + inLanguages((t) => t('set.system.lead')) + '</p></div>' +
|
|
49
|
+
// Not `set-msg-opt`: that row hangs from Alerts' first on a line, and this one hangs from nothing.
|
|
50
|
+
'<article class="set-msg' + (on ? ' set-msg-on' : '') + '"><div class="set-card-body">' +
|
|
51
|
+
'<div class="set-card-name"><h3 class="set-msg-name">' + inLanguages((t) => t('set.system.name')) + '</h3></div>' +
|
|
52
|
+
'<p class="set-msg-why">' + inLanguages((t) => t('set.system.when')) + '</p>' +
|
|
53
|
+
// As Alerts' optional rows: where the hooks are unknown, so is whether anything is said at all - the switch alone.
|
|
54
|
+
(view.known ? stateLine({ key: on ? 'set.state.on' : 'set.state.off', on }) : '') +
|
|
55
|
+
'<p class="set-say" data-set-say hidden></p></div>' +
|
|
56
|
+
toggleSwitch({
|
|
57
|
+
on,
|
|
58
|
+
disabled: !view.noticesWritable,
|
|
59
|
+
attributes: labelAttributes((t) => t('set.system.name')) + ' data-set-notice="' + e(JSON.stringify({ notify: next })) + '"',
|
|
60
|
+
}) +
|
|
61
|
+
'</article></section>';
|
|
62
|
+
}
|
|
31
63
|
/**
|
|
32
64
|
* W25a: the onboarding again, where this run serves it - drawn as Uninstall is (a mark, one sentence, the button), and
|
|
33
65
|
* above it: going through the setup again comes before taking it all out. Nothing is written until its Finish (W10).
|
|
@@ -115,6 +115,8 @@ const SETTINGS_STYLE = String.raw `
|
|
|
115
115
|
.set-cannot{margin:-8px 0 22px}
|
|
116
116
|
.set-quiet{font-size:14px;line-height:1.5;color:var(--text-3)}
|
|
117
117
|
.set-soft{color:var(--text-2)}
|
|
118
|
+
.set-tick{display:flex;gap:10px;align-items:flex-start;font-size:14px;color:var(--text-2);cursor:pointer}
|
|
119
|
+
.set-tick input{margin-top:3px;accent-color:var(--coral)}
|
|
118
120
|
.set-head{margin-bottom:16px}
|
|
119
121
|
.co+.set-head{margin-top:30px}
|
|
120
122
|
.set-h2{margin:0;font-size:19px;font-weight:650;line-height:1.3}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* What only Settings does (`.ai/plans/2026-09-23-settings-redesign.md`, step 3). The kit opens and closes the windows
|
|
3
5
|
* and switches the tabs; this posts what a confirm button carries, and reads the page again once the server has
|
|
@@ -43,7 +45,7 @@ export const SETTINGS_SCRIPT = String.raw `
|
|
|
43
45
|
if (body.change === 'protect') return 'agentwhy init --protect ' + quote(body.pattern) + ' --refuse' + shared(body.where);
|
|
44
46
|
if (body.change === 'adopt') return 'agentwhy init' + body.patterns.map((pattern) => ' --protect ' + quote(pattern)).join('') + ' --refuse' + shared(body.where);
|
|
45
47
|
if (body.change === 'unprotect') return 'agentwhy init --remove --unprotect ' + quote(body.pattern) + shared(body.where);
|
|
46
|
-
if (body.scope === 'project') return 'agentwhy notify' + (body.on ? ' --on ' + body.on : '') + (body.clean ? ' --clean ' + body.clean : '');
|
|
48
|
+
if (body.scope === 'project') return 'agentwhy notify' + (body.on ? ' --on ' + body.on : '') + (body.clean ? ' --clean ' + body.clean : '') + (body.notify ? ' --notify ' + body.notify.join(',') : '');
|
|
47
49
|
return '';
|
|
48
50
|
};
|
|
49
51
|
|
|
@@ -101,6 +103,11 @@ export const SETTINGS_SCRIPT = String.raw `
|
|
|
101
103
|
const picked = document.querySelector('input[name="' + confirm.dataset.setWho + '"]:checked');
|
|
102
104
|
body.where = picked ? picked.value : 'local';
|
|
103
105
|
}
|
|
106
|
+
// AO17: the window's unticked choice - out of the person's own Codex files too, only when ticked.
|
|
107
|
+
if (confirm.dataset.setTick) {
|
|
108
|
+
const tick = document.querySelector('input[name="' + confirm.dataset.setTick + '"]');
|
|
109
|
+
if (tick && tick.checked) body.codex = true;
|
|
110
|
+
}
|
|
104
111
|
change(body, confirm, confirm.getAttribute('data-set-command-' + (body.where || 'local')));
|
|
105
112
|
return;
|
|
106
113
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { DEFAULT_POLICY } from '../../../core/policy/default-policy.js';
|
|
4
|
+
import { matchesGlob } from '../../../core/policy/glob.js';
|
|
2
5
|
import { SETTINGS_FILES } from '../../../adapter/claude-code/contract/settings.js';
|
|
3
6
|
import { DEFAULT_THRESHOLD } from '../../watch/agent-alert.js';
|
|
4
|
-
import { DEFAULT_CLEAN } from '../../watch/notice-choices.js';
|
|
7
|
+
import { DEFAULT_CHANNELS, DEFAULT_CLEAN } from '../../watch/notice-choices.js';
|
|
5
8
|
import { RULE_NAMES } from '../../rule-names.js';
|
|
6
9
|
/**
|
|
7
10
|
* What the Settings page shows, decided from what the files hold (`for-people-who-build-with-ai.md` §3 C; the plan's
|
|
@@ -32,7 +35,9 @@ export function settingsView(settings) {
|
|
|
32
35
|
const read = known ? readPatterns(settings, reads) : undefined;
|
|
33
36
|
const told = toldIn(settings);
|
|
34
37
|
const canTell = canWrite && settings.told !== undefined && settings.told.local !== 'unreadable' && settings.told.shared !== 'unreadable';
|
|
35
|
-
const rows = read === undefined
|
|
38
|
+
const rows = read === undefined
|
|
39
|
+
? policyRows(settings)
|
|
40
|
+
: fileRows(settings, reads, read, told, canTell).map((row) => coveredOf(keptOf(row, settings, hooks), settings, told));
|
|
36
41
|
const unread = read === undefined ? [] : unreadRules(settings, read);
|
|
37
42
|
const addTo = reads === 'local' || reads === 'shared' ? reads : alerts.who ?? stop.who ?? 'local';
|
|
38
43
|
// A built-in pattern on a told list is read and told, never blocked again by an add (F57).
|
|
@@ -45,6 +50,7 @@ export function settingsView(settings) {
|
|
|
45
50
|
stopped: { on: on === 'refused', locked: known && !alerts.on },
|
|
46
51
|
fine: { on: clean !== 'off', locked: known && !alerts.on },
|
|
47
52
|
noticesWritable: notices !== undefined && !notices.unusable,
|
|
53
|
+
system: { on: (notices?.notify ?? DEFAULT_CHANNELS).includes('os'), channels: notices?.notify ?? DEFAULT_CHANNELS },
|
|
48
54
|
stop,
|
|
49
55
|
scope,
|
|
50
56
|
moves: { local: movesInto(settings, hooks, 'local'), shared: movesInto(settings, hooks, 'shared') },
|
|
@@ -189,6 +195,27 @@ function keptOf(row, settings, hooks) {
|
|
|
189
195
|
const whole = ruled.length === row.patterns.length && (searched === undefined || row.patterns.every((pattern) => searched.has(pattern)));
|
|
190
196
|
return whole ? row : { ...row, kept: 'open' };
|
|
191
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* SW19, found by the maintainer on 2026-10-02: `demo.env` was switched to Track, and Claude Code still refused every
|
|
200
|
+
* read - its own deny rule for every `.env` file covers that name, and deny rules know no exceptions. The row carries
|
|
201
|
+
* the shortest written Block rule that still matches the row's file, by the name a command or a path would use. Only
|
|
202
|
+
* a row tracked by a file's name is asked - a folder or a hand-written pattern names no one file to try - and only
|
|
203
|
+
* rules a settings file actually holds count, because only those are rules Claude Code applies itself.
|
|
204
|
+
*/
|
|
205
|
+
function coveredOf(row, settings, told) {
|
|
206
|
+
if (row.mode !== 'tell' || !row.watched)
|
|
207
|
+
return row;
|
|
208
|
+
const names = row.patterns.flatMap((pattern) => {
|
|
209
|
+
const name = /^\*\*\/([^*?/]+)$/.exec(pattern)?.[1];
|
|
210
|
+
return name === undefined ? [] : [name];
|
|
211
|
+
});
|
|
212
|
+
if (names.length === 0)
|
|
213
|
+
return row;
|
|
214
|
+
const written = FILES.flatMap((file) => settings.held?.[file] ?? []).filter((pattern) => !told.has(pattern));
|
|
215
|
+
const covering = written.filter((pattern) => names.some((name) => matchesGlob(name, pattern) || matchesGlob(`a/${name}`, pattern)));
|
|
216
|
+
const covered = covering.sort((one, two) => one.length - two.length || (one < two ? -1 : 1))[0];
|
|
217
|
+
return covered === undefined ? row : { ...row, covered };
|
|
218
|
+
}
|
|
192
219
|
function denied(settings, pattern) {
|
|
193
220
|
return FILES.some((file) => settings.held?.[file]?.includes(pattern) ?? false);
|
|
194
221
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages } from '../../render/report-copy.js';
|
|
3
5
|
import { addFilePopup } from '../../render/ui/add-file-popup.js';
|
|
@@ -115,18 +117,25 @@ function uninstallWindow(view) {
|
|
|
115
117
|
return '';
|
|
116
118
|
const command = files.map((file) => 'agentwhy init --remove --watch --refuse' +
|
|
117
119
|
(view.uninstall[file] ?? []).map((rule) => ' --unprotect ' + quoted(rule)).join('') + shared(file)).join(' && ');
|
|
120
|
+
// AO17: one project's uninstall leaves agentwhy's check in the person's own Codex settings for the other projects
|
|
121
|
+
// (AOD4) - said here, with the unticked choice that takes it out of Codex too.
|
|
122
|
+
const codex = view.codex === undefined ? '' :
|
|
123
|
+
'<label class="set-tick"><input type="checkbox" name="set-uninstall-codex">' +
|
|
124
|
+
'<span>' + inLanguages((t) => t('set.confirm.uninstall.codex')) + '</span></label>';
|
|
118
125
|
return confirmDialog({
|
|
119
126
|
id: UNINSTALL_WINDOW,
|
|
120
127
|
glyph: '',
|
|
121
128
|
title: inLanguages((t) => t('set.confirm.uninstall')),
|
|
122
129
|
subject: '',
|
|
123
130
|
sentence: inLanguages((t) => t('set.confirm.uninstall.text') + (files.includes('shared') ? ' ' + t('set.confirm.everyone') : '')),
|
|
124
|
-
option:
|
|
131
|
+
option: codex,
|
|
125
132
|
note: say(),
|
|
126
133
|
cancel: inLanguages((t) => t('app.cancel')),
|
|
127
134
|
confirm: inLanguages((t) => t('set.confirm.uninstall.go')),
|
|
128
135
|
tone: 'primary',
|
|
129
|
-
confirmAttributes: write({ change: 'uninstall', rules: view.uninstall }) +
|
|
136
|
+
confirmAttributes: write({ change: 'uninstall', rules: view.uninstall }) +
|
|
137
|
+
(view.codex === undefined ? '' : ' data-set-tick="set-uninstall-codex"') +
|
|
138
|
+
commandAttribute('local', command),
|
|
130
139
|
});
|
|
131
140
|
}
|
|
132
141
|
/** The hooks a file runs once the moved ones are in it: `init` with hook flags takes out any it is not given (R4b). */
|
|
@@ -167,11 +176,13 @@ function finishWindow(view) {
|
|
|
167
176
|
});
|
|
168
177
|
}
|
|
169
178
|
/**
|
|
170
|
-
*
|
|
171
|
-
* every block - and the honesty line under it. Opened
|
|
179
|
+
* `codex-approves-its-own-hook` AO8, AO10: agentwhy's Codex check, written to the person's own files and approved by
|
|
180
|
+
* agentwhy itself - the page's confirmation is the consent, as for every block - and the honesty line under it. Opened
|
|
181
|
+
* from `off` and from `stale` alike: the same write installs and heals. Opened as a file, it hands over
|
|
182
|
+
* `agentwhy init --codex`.
|
|
172
183
|
*/
|
|
173
184
|
function codexWindow(view) {
|
|
174
|
-
if (view.codex !== 'off' || !view.stop.on)
|
|
185
|
+
if ((view.codex !== 'off' && view.codex !== 'stale') || !view.stop.on)
|
|
175
186
|
return '';
|
|
176
187
|
return confirmDialog({
|
|
177
188
|
id: CODEX_WINDOW,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages } from '../../render/report-copy.js';
|
|
3
5
|
import { textButton } from '../../render/ui/button.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
5
|
import { closeButton, pill } from '../../render/ui/button.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
5
|
import { pill } from '../../render/ui/button.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { matchesGlob } from '../../../core/policy/glob.js';
|
|
2
4
|
import { idInKey } from '../../../core/session-catalogue.js';
|
|
3
5
|
import { escapeHtml as e } from '../../render/html-report-components.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* What only To fix does (`.ai/plans/2026-09-23-to-fix-redesign.md`, step 3). The kit opens and closes the windows and
|
|
3
5
|
* switches the tabs, and the Fix it wizard writes a mark; this posts an undo, and reads the page again once the server
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sumRefusedByOthers } from '../refusals.js';
|
|
1
2
|
export const ALERT_THRESHOLDS = ['value', 'reached', 'refused'];
|
|
2
3
|
/**
|
|
3
4
|
* What is said when nobody has said otherwise: only a value written from a protected file. The other two are worth
|
|
@@ -32,6 +33,7 @@ export function alertOf(report, agentIndex) {
|
|
|
32
33
|
const wroteItself = node.wroteValue === true || node.wroteOnward === true || usedItself;
|
|
33
34
|
const reached = reachedFromReturn > 0 || node.filesReached > 0 || reachedBelow;
|
|
34
35
|
const refusedAttempts = subtree.reduce((sum, agent) => sum + agent.refusedAttempts, 0);
|
|
36
|
+
const byOthers = sumRefusedByOthers(subtree.map((agent) => agent.refusedByOthers));
|
|
35
37
|
const filesReached = own.length > 0 ? reachedFromReturn : reachedBelow ? undefined : node.filesReached;
|
|
36
38
|
const level = wroteOrReturnedValue || wroteItself ? 'value' : reached ? 'reached' : refusedAttempts > 0 ? 'refused' : 'nothing';
|
|
37
39
|
return {
|
|
@@ -40,6 +42,7 @@ export function alertOf(report, agentIndex) {
|
|
|
40
42
|
...(node.type === undefined ? {} : { type: node.type }),
|
|
41
43
|
...(filesReached === undefined ? {} : { filesReached }),
|
|
42
44
|
refusedAttempts,
|
|
45
|
+
...(byOthers === undefined ? {} : { refusedByOthers: byOthers }),
|
|
43
46
|
};
|
|
44
47
|
}
|
|
45
48
|
/** Whether a level is strong enough to be said, under the threshold asked for. */
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { SETTINGS_FILES } from '../../adapter/claude-code/contract/settings.js';
|
|
5
|
+
import { refuseProjectAbove, refuseRulesOf } from '../../adapter/claude-code/settings/refuse-project.js';
|
|
6
|
+
import { codexReaderOf } from '../../adapter/codex/hooks/reader.js';
|
|
7
|
+
import { codexConversationOf } from '../../adapter/codex/hooks/codex-conversation.js';
|
|
8
|
+
import { codexStopFolder, parseCodexStopInput } from '../../adapter/codex/hooks/stop-input.js';
|
|
9
|
+
import { sessionKey } from '../../core/session-catalogue.js';
|
|
10
|
+
import { FileAccessError } from '../../ports/file-access-error.js';
|
|
11
|
+
import { CODEX_REQUESTS } from './render/codex-request-words.js';
|
|
12
|
+
/**
|
|
13
|
+
* Codex's end of a turn, for `watch` (`2026-10-02-codex-says-it-too.md` CX1-CX7): its `Stop` read by Codex's names,
|
|
14
|
+
* who reads it from its rollout, the commands agentwhy stopped in the turn, Codex's requests, a Codex session's key, and
|
|
15
|
+
* the project's rules - the ones Codex's `refuse` reads.
|
|
16
|
+
*/
|
|
17
|
+
export function codexTurnFormat(files, refusals, threadIndexPath, home) {
|
|
18
|
+
return {
|
|
19
|
+
readStop: parseCodexStopInput,
|
|
20
|
+
readerOf: (turn) => codexReaderOf(files, turn.transcriptPath),
|
|
21
|
+
stoppedIn: (text) => refusals.find(text),
|
|
22
|
+
requests: CODEX_REQUESTS,
|
|
23
|
+
sessionKey: (id) => sessionKey({ id, provider: 'codex' }),
|
|
24
|
+
settingsFor: (text) => rulesOfProject(files, codexStopFolder(text), home),
|
|
25
|
+
// CX8: one conversation across the session ids the Codex apps give it (CXB5).
|
|
26
|
+
conversationOf: (turn) => codexConversationOf(files, threadIndexPath, turn.sessionId),
|
|
27
|
+
// CX9 with AO5: watched where a project above the turn's folder runs `refuse` - as `refuse --codex` finds it.
|
|
28
|
+
watchedHere: async (text) => {
|
|
29
|
+
const folder = codexStopFolder(text);
|
|
30
|
+
return folder !== undefined && (await refuseProjectAbove(files, folder, home)) !== undefined;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* CX5 with AO5, AO6: the project is found as `refuse --codex` finds it - the nearest folder short of home whose Claude
|
|
36
|
+
* Code settings run `refuse` - and its rules are the settings file that project's `refuse` command names. Found by
|
|
37
|
+
* review: guessing the local file first read no rules where a project keeps them in the shared one, and so said a chat
|
|
38
|
+
* was clean over a file `refuse` protects. Where it names none, the local file, then the shared one, as before. A
|
|
39
|
+
* policy file is not a settings path, so it reads as none.
|
|
40
|
+
*/
|
|
41
|
+
async function rulesOfProject(files, folder, home) {
|
|
42
|
+
if (folder === undefined)
|
|
43
|
+
return undefined;
|
|
44
|
+
const found = await refuseProjectAbove(files, folder, home);
|
|
45
|
+
if (found === undefined)
|
|
46
|
+
return undefined;
|
|
47
|
+
const rules = refuseRulesOf(found);
|
|
48
|
+
if (rules.policyPath !== undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
if (rules.settingsPath !== undefined)
|
|
51
|
+
return rules.settingsPath;
|
|
52
|
+
for (const name of [SETTINGS_FILES.local, SETTINGS_FILES.shared]) {
|
|
53
|
+
const settings = join(found.project, SETTINGS_FILES.directory, name);
|
|
54
|
+
if (await readable(files, settings))
|
|
55
|
+
return settings;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
async function readable(files, path) {
|
|
60
|
+
try {
|
|
61
|
+
await files.readText(path);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof FileAccessError)
|
|
66
|
+
return false;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* The choices a notice can be given, in a module of their own so that both the code that says a notice and the code
|
|
3
5
|
* that remembers what a person chose can name them without depending on each other.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { isJsonObject, parseJsonObject } from '../../shared/json.js';
|
|
2
4
|
import { ALERT_THRESHOLDS } from './agent-alert.js';
|
|
3
5
|
import { CLEAN_MODES, NOTICE_CHANNELS, NOTICE_LANGS, SAID_AS, } from './notice-choices.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The stopped limit says "now": told to never read the file another way, the agent refused to try again later in the
|
|
3
|
+
* same conversation after the person had switched the file to Track (seen by the maintainer, 2026-10-02). The hook is
|
|
4
|
+
* the gate, not the agent's memory of this sentence.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* What Codex's agent is handed (`2026-10-02-codex-says-it-too.md` CX2, CX3, amended 2026-10-02). Codex shows it whole, in
|
|
8
|
+
* a bubble above the reply (CXB1, CKB14), and the maintainer found the first wording - written to the agent, with the
|
|
9
|
+
* report's command in it - too long and not understandable for the person who reads it first. So each is written to the
|
|
10
|
+
* person: what happened and what to do, in one or two sentences of the glossary's words, in the language chosen for
|
|
11
|
+
* agentwhy; then, in brackets and marked as the AI's ("For the AI:", chosen by the maintainer so a person does not read it
|
|
12
|
+
* as said to them), the one thing the agent is asked - one short sentence back - with the limit that keeps
|
|
13
|
+
* the file safe: never show a key, never read a stopped file another way. No command, no report offered: the report is
|
|
14
|
+
* one step away in Conversations, and a command in that bubble is a line a person cannot read.
|
|
15
|
+
*/
|
|
16
|
+
export const CODEX_REQUESTS = {
|
|
17
|
+
stopped: (paths, lang) => STOPPED[lang](listed(paths, lang), paths.length === 1),
|
|
18
|
+
keys: (files, _command, lang) => KEYS[lang](listed(files.map(String), lang), files.length <= 1),
|
|
19
|
+
template: (files, _command, lang) => TEMPLATE[lang](listed(files.map(String), lang), files.length <= 1),
|
|
20
|
+
data: (files, _command, lang) => DATA[lang](listed(files.map(String), lang), files.length <= 1),
|
|
21
|
+
told: (files, _command, lang, foldsTurn) => TOLD[lang](listed(files.map(String), lang), files.length <= 1, foldsTurn === true),
|
|
22
|
+
quiet: (lang, foldsTurn) => QUIET[lang](foldsTurn === true),
|
|
23
|
+
};
|
|
24
|
+
const STOPPED = {
|
|
25
|
+
en: (files, one) => `**agentwhy** stopped your AI from reading the private ${one ? 'file' : 'files'} ${files}. ` +
|
|
26
|
+
`(For the AI: reply in one short sentence, and don't try to read ${one ? 'it' : 'them'} another way now.)`,
|
|
27
|
+
pl: (files, one) => `**agentwhy** nie pozwolił AI odczytać ${one ? 'prywatnego pliku' : 'prywatnych plików'} ${files}. ` +
|
|
28
|
+
`(Dla AI: odpowiedz jednym krótkim zdaniem i nie próbuj teraz odczytać ${one ? 'go' : 'ich'} inaczej.)`,
|
|
29
|
+
de: (files, one) => `**agentwhy** hat deine KI daran gehindert, ${one ? 'die private Datei' : 'die privaten Dateien'} ${files} zu lesen. ` +
|
|
30
|
+
`(Für die KI: antworte in einem kurzen Satz und versuch jetzt nicht, sie anders zu lesen.)`,
|
|
31
|
+
};
|
|
32
|
+
const KEYS = {
|
|
33
|
+
en: (files, one) => `**agentwhy**: a key from the private ${one ? 'file' : 'files'} ${files} is now in this chat. Make a new key ` +
|
|
34
|
+
`today where it was created; deleting the chat won't undo it. (For the AI: reply in one short sentence; don't show the key.)`,
|
|
35
|
+
pl: (files, one) => `**agentwhy**: klucz z ${one ? 'prywatnego pliku' : 'prywatnych plików'} ${files} jest teraz w tej rozmowie. ` +
|
|
36
|
+
`Zrób dziś nowy klucz tam, gdzie go utworzono; usunięcie rozmowy tego nie cofnie. (Dla AI: odpowiedz jednym krótkim ` +
|
|
37
|
+
`zdaniem; nie pokazuj klucza.)`,
|
|
38
|
+
de: (files, one) => `**agentwhy**: Ein Schlüssel aus ${one ? 'der privaten Datei' : 'den privaten Dateien'} ${files} ist jetzt ` +
|
|
39
|
+
`in diesem Chat. Erstelle heute dort einen neuen, wo er erstellt wurde; den Chat zu löschen hilft nicht. (Für die KI: ` +
|
|
40
|
+
`antworte in einem kurzen Satz; zeig den Schlüssel nicht.)`,
|
|
41
|
+
};
|
|
42
|
+
/** A template's value may be a placeholder: only a real key is to be made new (S6, `template`). */
|
|
43
|
+
const TEMPLATE = {
|
|
44
|
+
en: (files, one) => `**agentwhy**: a value from the template ${one ? 'file' : 'files'} ${files} is now in this chat. If it's a ` +
|
|
45
|
+
`real key, make a new one where it was created. (For the AI: reply in one short sentence; don't show the value.)`,
|
|
46
|
+
pl: (files, one) => `**agentwhy**: wartość z ${one ? 'pliku-szablonu' : 'plików-szablonów'} ${files} jest teraz w tej rozmowie. ` +
|
|
47
|
+
`Jeśli to prawdziwy klucz, zrób nowy tam, gdzie go utworzono. (Dla AI: odpowiedz jednym krótkim zdaniem; ` +
|
|
48
|
+
`nie pokazuj tej wartości.)`,
|
|
49
|
+
de: (files, one) => `**agentwhy**: Ein Wert aus ${one ? 'der Vorlagendatei' : 'den Vorlagendateien'} ${files} ist jetzt in ` +
|
|
50
|
+
`diesem Chat. Ist es ein echter Schlüssel, erstelle dort einen neuen, wo er erstellt wurde. (Für die KI: antworte in ` +
|
|
51
|
+
`einem kurzen Satz; zeig den Wert nicht.)`,
|
|
52
|
+
};
|
|
53
|
+
/** Data cannot be made new, so nothing is asked to be changed (S6, `data`): what cannot be taken back, and where to look. */
|
|
54
|
+
const DATA = {
|
|
55
|
+
en: (files, one) => `**agentwhy**: private data from the private ${one ? 'file' : 'files'} ${files} is now in this chat. It ` +
|
|
56
|
+
`can't be taken back; agentwhy's report shows how to limit the damage. (For the AI: reply in one short sentence; don't repeat the data.)`,
|
|
57
|
+
pl: (files, one) => `**agentwhy**: prywatne dane z ${one ? 'prywatnego pliku' : 'prywatnych plików'} ${files} są teraz w tej ` +
|
|
58
|
+
`rozmowie. Nie da się tego cofnąć; raport agentwhy pokazuje, jak ograniczyć szkody. (Dla AI: odpowiedz jednym krótkim ` +
|
|
59
|
+
`zdaniem; nie powtarzaj tych danych.)`,
|
|
60
|
+
de: (files, one) => `**agentwhy**: Private Daten aus ${one ? 'der privaten Datei' : 'den privaten Dateien'} ${files} sind jetzt ` +
|
|
61
|
+
`in diesem Chat. Das lässt sich nicht zurücknehmen; der Bericht von agentwhy zeigt, wie du den Schaden begrenzt. (Für ` +
|
|
62
|
+
`die KI: antworte in einem kurzen Satz; wiederhole die Daten nicht.)`,
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Where the app folds the turn away (`foldsTurn`, the desktop app, CXB5's display note), told and quiet ask the
|
|
66
|
+
* answer back - decided by the maintainer, 2026-10-02, after a control run: with a block, the whole Apache-licence
|
|
67
|
+
* answer sat behind "Worked for ...", and the visible reply was one line about private files. The full answer, not a
|
|
68
|
+
brief one: the maintainer tried "repeat your answer" the same day and found the visible repeat more condensed than
|
|
69
|
+
the original the fold hides. A told file is one the
|
|
70
|
+
* person lets their AI read, so the repeat carries nothing that may not be here; keys, data and a stopped command
|
|
71
|
+
* keep their limits - what their fold hides is what must not be repeated. VS Code's Codex folds nothing, so there
|
|
72
|
+
* the one short sentence stays and nothing is said twice.
|
|
73
|
+
*/
|
|
74
|
+
const TOLD = {
|
|
75
|
+
en: (files, one, folds) => `**agentwhy**: your AI read the private ${one ? 'file' : 'files'} ${files}, which you let it read. ` +
|
|
76
|
+
`Nothing to do. (For the AI: ${folds ? 'repeat your full answer for the user, then that nothing needs doing' : 'reply in one short sentence'}.)`,
|
|
77
|
+
pl: (files, one, folds) => `**agentwhy**: AI przeczytało ${one ? 'prywatny plik' : 'prywatne pliki'} ${files}, na ${one ? 'który' : 'które'} ` +
|
|
78
|
+
`pozwoliłeś. Nic nie trzeba robić. (Dla AI: ${folds ? 'powtórz całą swoją odpowiedź dla użytkownika i dodaj, że nic nie trzeba robić' : 'odpowiedz jednym krótkim zdaniem'}.)`,
|
|
79
|
+
de: (files, one, folds) => `**agentwhy**: Deine KI hat ${one ? 'die private Datei' : 'die privaten Dateien'} ${files} gelesen, die du ` +
|
|
80
|
+
`ihr erlaubt hast. Nichts zu tun. (Für die KI: ${folds ? 'wiederhole deine ganze Antwort für den Nutzer und ergänze, dass nichts zu tun ist' : 'antworte in einem kurzen Satz'}.)`,
|
|
81
|
+
};
|
|
82
|
+
const QUIET = {
|
|
83
|
+
en: (folds) => '**agentwhy** is keeping watch over your private files: none has been opened so far. ' +
|
|
84
|
+
`(For the AI: ${folds ? 'repeat your full answer for the user, then this in one sentence' : 'reply in one short sentence'}.)`,
|
|
85
|
+
pl: (folds) => '**agentwhy** pilnuje twoich prywatnych plików: jak dotąd żaden nie został otwarty. ' +
|
|
86
|
+
`(Dla AI: ${folds ? 'powtórz całą swoją odpowiedź dla użytkownika i dodaj to jednym zdaniem' : 'odpowiedz jednym krótkim zdaniem'}.)`,
|
|
87
|
+
de: (folds) => '**agentwhy** passt auf deine privaten Dateien auf: Bisher wurde keine geöffnet. ' +
|
|
88
|
+
`(Für die KI: ${folds ? 'wiederhole deine ganze Antwort für den Nutzer und ergänze dies in einem Satz' : 'antworte in einem kurzen Satz'}.)`,
|
|
89
|
+
};
|
|
90
|
+
/** At most three files by name, then how many more: a request a person reads is not a list. */
|
|
91
|
+
function listed(paths, lang) {
|
|
92
|
+
const named = [...new Set(paths)].slice(0, 3);
|
|
93
|
+
const rest = new Set(paths).size - named.length;
|
|
94
|
+
const and = AND[lang];
|
|
95
|
+
if (rest > 0)
|
|
96
|
+
named.push(MORE[lang](rest));
|
|
97
|
+
if (named.length <= 1)
|
|
98
|
+
return named[0] ?? '';
|
|
99
|
+
return `${named.slice(0, -1).join(', ')} ${and} ${named.at(-1)}`;
|
|
100
|
+
}
|
|
101
|
+
const AND = { en: 'and', pl: 'i', de: 'und' };
|
|
102
|
+
const MORE = {
|
|
103
|
+
en: (count) => `${count} more`,
|
|
104
|
+
pl: (count) => `${count} innych`,
|
|
105
|
+
de: (count) => `${count} weitere`,
|
|
106
|
+
};
|