@agentwhy/cli 0.1.0 → 0.2.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/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/command-router.js +8 -2
- 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 +12 -1
- package/dist/composition-root.js +101 -16
- 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 +94 -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-decision.js +44 -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 +21 -2
- 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 +80 -55
- 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, LANGS, TABLES, translator } from '../../render/report-copy.js';
|
|
3
5
|
import { APP_SIDEBAR_STYLE } from '../../render/ui/app-sidebar.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* What the pages read through periods do with a script - Conversations, a week at a time, and This month
|
|
3
5
|
* (`for-people-who-build-with-ai.md` F10-F14; `.ai/plans/2026-09-23-month-redesign.md`): one period shown at a time, a
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { rangeName, tileName } from '../../render/ui/local-date.js';
|
|
2
4
|
import { inLanguages } from '../../render/report-copy.js';
|
|
3
5
|
import { dayTile, periodSwitch } from './calendar-view.js';
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { printable } from '../../shared/printable.js';
|
|
2
|
+
import { quietlySaid } from './render/start-words.js';
|
|
3
|
+
/**
|
|
4
|
+
* How long a server started in the background is waited for, at most, while its process runs (PF3): its first pages are
|
|
5
|
+
* every conversation of the project, and a project with many takes a while. A process that ended is not waited for -
|
|
6
|
+
* a sandbox, a port refused - and the pages are written as files at once.
|
|
7
|
+
*/
|
|
8
|
+
const WAIT_MS = 60_000;
|
|
9
|
+
const ASK_EVERY_MS = 250;
|
|
10
|
+
/**
|
|
11
|
+
* `start --detach` (`2026-10-02-a-page-not-a-file.md` PF3-PF5): the pages served, from a command that returns at once.
|
|
12
|
+
* A server already running for this project is used - its address stays the one the person has open; else one is
|
|
13
|
+
* started in the background and waited for; else, where none can start (a sandbox), the pages are written as files,
|
|
14
|
+
* as `--no-serve` writes them, and that is said with what to do.
|
|
15
|
+
*/
|
|
16
|
+
export class DetachedStart {
|
|
17
|
+
#dependencies;
|
|
18
|
+
constructor(dependencies) {
|
|
19
|
+
this.#dependencies = dependencies;
|
|
20
|
+
}
|
|
21
|
+
async run(options) {
|
|
22
|
+
const { servers, probe, background, project, clock, sleep } = this.#dependencies;
|
|
23
|
+
const known = await servers.read(project);
|
|
24
|
+
if (known !== undefined && (await probe.answers(`${known.url}index.html`)))
|
|
25
|
+
return this.#show(known.url, options, true);
|
|
26
|
+
const pid = await background.start(backgroundArgs(options));
|
|
27
|
+
if (pid !== undefined) {
|
|
28
|
+
for (const deadline = clock() + WAIT_MS; clock() < deadline; await sleep(ASK_EVERY_MS)) {
|
|
29
|
+
const started = await servers.read(project);
|
|
30
|
+
if (started?.pid === pid && (await probe.answers(`${started.url}index.html`)))
|
|
31
|
+
return this.#show(started.url, options, false);
|
|
32
|
+
if (!background.running(pid))
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return this.#asFiles(options);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The page asked for on a running server: the session's report where it serves one (SW10), else the welcome where
|
|
40
|
+
* this project is to meet it (AW1), else every conversation.
|
|
41
|
+
*/
|
|
42
|
+
async #show(base, options, reused) {
|
|
43
|
+
const { probe, browser } = this.#dependencies;
|
|
44
|
+
const asked = options.session === undefined ? undefined : `${base}${options.session}.html`;
|
|
45
|
+
const found = asked === undefined || (await probe.answers(asked));
|
|
46
|
+
const welcome = await this.#welcome(asked);
|
|
47
|
+
const url = asked !== undefined && found ? asked : `${base}${welcome?.file ?? 'index.html'}`;
|
|
48
|
+
const opened = options.open && (await browser.open(url));
|
|
49
|
+
// A conversation asked for and not served is said in every output, never passed off as its report (SW10).
|
|
50
|
+
const missing = found ? '' : 'That conversation was not found here, so all conversations are served.\n';
|
|
51
|
+
// Not opened, a served page is still there to open: said as served, never as a file written.
|
|
52
|
+
if (options.quiet === true)
|
|
53
|
+
return { outcome: 'written', output: opened ? quietlySaid(url, true, found) : `${missing}Serving: ${url}\n` };
|
|
54
|
+
return {
|
|
55
|
+
outcome: 'written',
|
|
56
|
+
output: missing +
|
|
57
|
+
`${reused ? 'agentwhy was already running for this project' : 'agentwhy runs in the background for this project'}: ${url}\n` +
|
|
58
|
+
// AWD3's sentence, in the words a served run already prints: true whether or not anyone opens the address.
|
|
59
|
+
(welcome === undefined
|
|
60
|
+
? ''
|
|
61
|
+
: `${opened ? 'Opened' : 'That address opens'} the welcome page, to set agentwhy up for ${printable(welcome.project)}.\n`) +
|
|
62
|
+
'It stops by itself 30 minutes after its last page is closed.\n',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* AW1: the onboarding's file where this run's address is to name it. A conversation asked for is the person's own
|
|
67
|
+
* yes to that report and wins over a setup they did not ask for, as a served run's own page does (SW10).
|
|
68
|
+
*/
|
|
69
|
+
async #welcome(asked) {
|
|
70
|
+
const { welcome } = this.#dependencies;
|
|
71
|
+
if (asked !== undefined || welcome === undefined || !(await welcome.opens()))
|
|
72
|
+
return undefined;
|
|
73
|
+
return { file: welcome.file, project: welcome.project };
|
|
74
|
+
}
|
|
75
|
+
/** PF4: no server came up - a sandbox, a refusal - so the pages are files, and what would serve them is said. */
|
|
76
|
+
async #asFiles(options) {
|
|
77
|
+
const written = await this.#dependencies.files.run({ ...options, serve: false });
|
|
78
|
+
return {
|
|
79
|
+
...written,
|
|
80
|
+
output: 'agentwhy could not keep running in the background here, so the pages were written as files. To open them live, ' +
|
|
81
|
+
'run this command again outside the sandbox, or type npx @agentwhy/cli in a terminal.\n' + written.output,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** What the server in the background is started with: the same choices, served, opening nothing of its own. */
|
|
86
|
+
function backgroundArgs(options) {
|
|
87
|
+
return [
|
|
88
|
+
'start', '--serve', '--no-open', '--since', options.since.asked,
|
|
89
|
+
...(options.out === undefined ? [] : ['--out', options.out]),
|
|
90
|
+
...(options.policyPath === undefined ? [] : ['--policy', options.policyPath]),
|
|
91
|
+
...(options.settingsPath === undefined ? [] : ['--settings', options.settingsPath]),
|
|
92
|
+
...(options.session === undefined ? [] : ['--session', options.session]),
|
|
93
|
+
];
|
|
94
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { dataTable } from '../../render/ui/data-table.js';
|
|
2
4
|
import { closeButton, pill } from '../../render/ui/button.js';
|
|
3
5
|
import { CLOSES, popup, popupFoot } from '../../render/ui/popup.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 } from '../../render/report-copy.js';
|
|
3
5
|
import { BRAND_MARK } from '../../render/ui/brand-mark.js';
|
|
@@ -82,14 +84,18 @@ function nothing(done, links) {
|
|
|
82
84
|
: '<div class="ob-good"><span class="ob-good-mark" aria-hidden="true">✓</span><span>' +
|
|
83
85
|
'<span class="ob-good-title">' + inLanguages((t) => t('ob.done.good')) + '</span>' +
|
|
84
86
|
'<span class="ob-good-text">' + inLanguages((t) => t('ob.done.good.text', { when: when(t, done.asked) })) + '</span></span></div>') +
|
|
85
|
-
|
|
87
|
+
openAgentwhy(links);
|
|
86
88
|
}
|
|
87
|
-
/** W1a: no AI chats yet - set up before there is anything to show, and
|
|
89
|
+
/** W1a: no AI chats yet - set up before there is anything to show, and then Conversations, where they will be listed. */
|
|
88
90
|
function empty(links) {
|
|
89
91
|
return '<h2 class="ob-h2 ob-done-title" id="ob-done-title"><span data-ob-if="on">' + inLanguages((t) => t('ob.done.protected')) + '</span>' +
|
|
90
92
|
'<span data-ob-if="off" hidden>' + inLanguages((t) => t('ob.done.empty.title')) + '</span></h2>' +
|
|
91
93
|
'<p class="ob-done-text">' + inLanguages((t) => t('ob.done.empty.text')) + '</p>' +
|
|
92
|
-
|
|
94
|
+
openAgentwhy(links);
|
|
95
|
+
}
|
|
96
|
+
/** W19, W1a: Done's own way on, to Conversations, whether or not there are chats in it yet. */
|
|
97
|
+
function openAgentwhy(links) {
|
|
98
|
+
return '<div class="ob-done-go">' + pill({ label: inLanguages((t) => t('ob.done.open')), tone: 'mint', size: 'lg', href: links.conversations }) + '</div>';
|
|
93
99
|
}
|
|
94
100
|
/** "From now on, you'll be told right away." - or, where alerts end up off, how to turn them on (W18). */
|
|
95
101
|
function told() {
|
|
@@ -24,11 +24,13 @@ export async function finishOnboarding(dependencies, choices) {
|
|
|
24
24
|
for (const change of changes)
|
|
25
25
|
results.push(await written(dependencies, change, choices.scope, telling));
|
|
26
26
|
const recorded = await dependencies.store.add(dependencies.clock());
|
|
27
|
-
// W20a: read from the files as Finish left them - the writes above go through `CodexMirror`, which writes
|
|
28
|
-
// with Claude Code's `refuse` - and said only where Claude Code's block runs, so a project that blocks
|
|
29
|
-
// told Codex isn't blocked.
|
|
27
|
+
// W20a: read from the files as Finish left them - the writes above go through `CodexMirror`, which writes agentwhy's
|
|
28
|
+
// Codex check with Claude Code's `refuse` - and said only where Claude Code's block runs, so a project that blocks
|
|
29
|
+
// nothing is not told Codex isn't blocked. `on` only where the check is verified (AO3): a write that did not verify
|
|
30
|
+
// reads as `off`, whose line says Settings can make it.
|
|
30
31
|
const after = (await dependencies.settingsNow()).hooks;
|
|
31
|
-
const
|
|
32
|
+
const state = after !== undefined && after.refuse !== false ? after.codex : undefined;
|
|
33
|
+
const codex = state === 'stale' ? 'off' : state;
|
|
32
34
|
return { outcome: 'finished', results, recorded, ...(codex === undefined ? {} : { codex }) };
|
|
33
35
|
}
|
|
34
36
|
async function written(dependencies, change, scope, telling) {
|
|
@@ -43,7 +43,6 @@ export class OnboardingRenderer {
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
#page(view, index) {
|
|
46
|
-
const anyConversation = index.entries.length > 0;
|
|
47
46
|
// which-project V7: in the home directory there is no project to set up - only the step that picks one.
|
|
48
47
|
const project = view.project.kind === 'none' ? undefined : view.project.name;
|
|
49
48
|
const state = {
|
|
@@ -62,7 +61,7 @@ export class OnboardingRenderer {
|
|
|
62
61
|
'<div class="ob-body">' + introScreen() + welcomeScreen() +
|
|
63
62
|
projectStep(view, { now: index.now, timeZone: index.timeZone ?? 'UTC' }) +
|
|
64
63
|
(project === undefined ? '' : stepScreens(view, project) + doneScreen(view.done, this.#links)) +
|
|
65
|
-
noScript(this.#links,
|
|
64
|
+
noScript(this.#links, project !== undefined) + '</div>' +
|
|
66
65
|
(view.files.canAdd && project !== undefined ? addFilePopup(ADD_WINDOW) : '') +
|
|
67
66
|
'</div>';
|
|
68
67
|
}
|
|
@@ -84,13 +83,14 @@ function header() {
|
|
|
84
83
|
/**
|
|
85
84
|
* W27: without a script nothing here can be written, so the page says where the same choices are made - where there is a
|
|
86
85
|
* project to make them for. In the home directory the project step already leads to its chats (which-project V7).
|
|
86
|
+
* Conversations is written for a project with no chats too (W1a, amended 2026-10-01), so both links are always there.
|
|
87
87
|
*/
|
|
88
|
-
function noScript(links,
|
|
88
|
+
function noScript(links, aProject) {
|
|
89
89
|
if (!aProject)
|
|
90
90
|
return '';
|
|
91
91
|
return '<div class="ob-nojs"><p>' + inLanguages((t) => t('ob.nojs')) + '</p><p class="ob-nojs-links">' +
|
|
92
92
|
pill({ label: inLanguages((t) => t('ob.nojs.settings')), tone: 'primary', size: 'lg', href: links.settings }) +
|
|
93
|
-
|
|
93
|
+
pill({ label: inLanguages((t) => t('ob.nojs.conversations')), tone: 'outline', size: 'lg', href: links.conversations }) +
|
|
94
94
|
'</p></div>';
|
|
95
95
|
}
|
|
96
96
|
/** What the script says, in every language: it cannot hold three languages in one text node. */
|
|
@@ -91,7 +91,7 @@ function projectOf(index, read) {
|
|
|
91
91
|
if (index.entries.length > 0)
|
|
92
92
|
return { kind: 'found', name, ...place, conversations: index.entries.length, entryPoints: index.entryPoints ?? {}, read };
|
|
93
93
|
const above = index.projects?.above;
|
|
94
|
-
const holder = above === undefined ? undefined : index.projects?.rows.find((row) => row.id === above.id && row.
|
|
94
|
+
const holder = above === undefined ? undefined : index.projects?.rows.find((row) => row.id === above.id && row.folder !== 'gone');
|
|
95
95
|
if (above !== undefined && holder !== undefined)
|
|
96
96
|
return { kind: 'inside', name, ...place, above: holder, within: above.within };
|
|
97
97
|
return { kind: 'empty', name, ...place };
|
|
@@ -7,7 +7,7 @@ import { tag } from '../../render/ui/tag.js';
|
|
|
7
7
|
/** The radio group the step's list chooses in (`.ai/specs/2026-09-27-which-project.md` V11). */
|
|
8
8
|
export const PICK_GROUP = 'ob-project';
|
|
9
9
|
/** The kinds V4 names, in the order the step says them; an unknown kind is counted last and not named. */
|
|
10
|
-
const NAMED = ['editor', 'terminal', 'script'];
|
|
10
|
+
const NAMED = ['editor', 'terminal', 'desktop', 'script'];
|
|
11
11
|
/** A small folder, drawn: the guidelines have no emoji, not even in a button (§9.3). */
|
|
12
12
|
const FOLDER_SVG = '<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true">' +
|
|
13
13
|
'<path d="M3 6.5A1.5 1.5 0 0 1 4.5 5h4.2l2 2.2h8.8A1.5 1.5 0 0 1 21 8.7v9.8a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 18.5z"/></svg>';
|
|
@@ -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, textButton, trashButton } from '../../render/ui/button.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
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 { notAProject } from '../../../setup/not-a-project.js';
|
|
6
|
+
import { readSettingsFile, setUpBy } from '../settings-files.js';
|
|
7
|
+
/**
|
|
8
|
+
* Whether a project's run should name the onboarding instead of the index (W23), and what else the page needs to know.
|
|
9
|
+
*
|
|
10
|
+
* Its one side effect is N6's: a project set up before this screen existed, or by hand, has its `done` line written
|
|
11
|
+
* here and silently, so that turning alerts off later never brings the onboarding back. Asking a second time for the
|
|
12
|
+
* same project writes no second line: that reading finds the first.
|
|
13
|
+
*
|
|
14
|
+
* Shared by every run that names a page - `start` itself, and `start --detach`, whose address is the only way a person
|
|
15
|
+
* reaches one (`2026-10-01-the-address-opens-the-welcome.md` AW1, extended to `--detach` on 2026-10-04).
|
|
16
|
+
*/
|
|
17
|
+
export async function welcomeIn(workingDirectory, asked) {
|
|
18
|
+
const { store, files, home, realHome, now } = asked;
|
|
19
|
+
const reading = await store.read();
|
|
20
|
+
// W24: the intro plays once per person - where no project of theirs has finished the onboarding.
|
|
21
|
+
const intro = !reading.anywhere && !reading.failed;
|
|
22
|
+
// which-project V7: in the home directory no project is being shown, so the onboarding opens at its project step,
|
|
23
|
+
// whatever the record says - after the welcome only for a person who has never finished one. Nothing here is set up
|
|
24
|
+
// and no record is kept of it: not even the silent `done` line below.
|
|
25
|
+
if (home !== undefined && notAProject(workingDirectory, home, realHome) !== undefined) {
|
|
26
|
+
return { opens: true, intro, setUp: false, ...(intro ? {} : { atProject: true }) };
|
|
27
|
+
}
|
|
28
|
+
if (reading.here)
|
|
29
|
+
return { opens: false, intro, setUp: true };
|
|
30
|
+
if (reading.failed)
|
|
31
|
+
return { opens: false, intro, setUp: false };
|
|
32
|
+
// A local file that cannot be read leaves what runs unknown, and the onboarding closed (as `#settingsNow` does).
|
|
33
|
+
const local = await readSettingsFile(files, join(workingDirectory, SETTINGS_FILES.directory, SETTINGS_FILES.local));
|
|
34
|
+
if (local === 'unreadable')
|
|
35
|
+
return { opens: false, intro, setUp: false };
|
|
36
|
+
const shared = await readSettingsFile(files, join(workingDirectory, SETTINGS_FILES.directory, SETTINGS_FILES.shared));
|
|
37
|
+
// N6, widened 2026-09-28 by the maintainer (which-project V10): a project where one of agentwhy's hooks runs, or whose
|
|
38
|
+
// settings block files, was set up - before this screen existed, or by hand - and is recorded so, silently.
|
|
39
|
+
if (setUpBy([local, shared])) {
|
|
40
|
+
await store.add(now());
|
|
41
|
+
return { opens: false, intro, setUp: true };
|
|
42
|
+
}
|
|
43
|
+
return { opens: true, intro, setUp: false };
|
|
44
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { join, relative } from 'node:path';
|
|
2
4
|
import { SETTINGS_FILES } from '../../../adapter/claude-code/contract/settings.js';
|
|
3
5
|
import { projectDirectoryName } from '../../../adapter/claude-code/contract/projects.js';
|
|
@@ -15,12 +17,13 @@ export async function indexProjects(listing, sources) {
|
|
|
15
17
|
const listed = temporary === undefined ? projects : projects.filter((project) => !temporary(project.path));
|
|
16
18
|
const finished = await sources.onboarding?.doneFor(listed.map((project) => projectDirectoryName(project.path)));
|
|
17
19
|
const rows = await Promise.all(listed.map(async (project) => {
|
|
18
|
-
|
|
20
|
+
// V10b: a folder not looked at is not read for its settings either.
|
|
21
|
+
const setUp = project.folder === 'there' ? await setUpIn(project, sources.files, finished) : undefined;
|
|
19
22
|
return {
|
|
20
23
|
id: project.id,
|
|
21
24
|
place: homeRelative(project.path, sources.home),
|
|
22
25
|
name: projectName(project.path),
|
|
23
|
-
|
|
26
|
+
folder: project.folder,
|
|
24
27
|
conversations: project.conversations,
|
|
25
28
|
newest: project.newest,
|
|
26
29
|
...(setUp === undefined ? {} : { setUp }),
|
|
@@ -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 { INDEX_CONTENT_SECURITY_POLICY_META } from '../../render/html-head.js';
|
|
3
5
|
import { inLanguages, LANGS, translator } from '../../render/report-copy.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, LANGS, translator } 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 { escapeHtml as e } from '../../render/html-report-components.js';
|
|
2
4
|
import { inLanguages, labelAttributes } from '../../render/report-copy.js';
|
|
3
5
|
import { BUTTON_STYLE, 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 { isAbsolute, relative, sep } from 'node:path';
|
|
2
4
|
/** Where systems keep what is thrown away: `/tmp`, and on macOS the per-person folders `TMPDIR` points into. */
|
|
3
5
|
const SYSTEM_TEMPORARY = ['/tmp', '/private/tmp', '/var/tmp', '/private/var/tmp', '/var/folders', '/private/var/folders'];
|
|
@@ -1,9 +1,22 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { paint } from '../../../shared/colour.js';
|
|
2
4
|
import { printable } from '../../../shared/printable.js';
|
|
3
5
|
import { TAGLINE, terminalLogo } from '../../../shared/terminal-logo.js';
|
|
4
6
|
const INDENT = ' ';
|
|
5
7
|
/** The mark a heading carries, as the report draws it (§4.1). It stands beside the word, never instead of it. */
|
|
6
8
|
const HEADING = '▍';
|
|
9
|
+
/**
|
|
10
|
+
* What `start --quiet` says (`2026-10-02-said-where-the-person-is.md` SW11): where the page is and whether it opened,
|
|
11
|
+
* nothing a report found. Its reader is the agent that ran it because the person said yes to a report, as for `report
|
|
12
|
+
* --quiet` (`the-agent-tells-you` R19). A conversation asked for and not found is said, never passed off as its report.
|
|
13
|
+
*/
|
|
14
|
+
export function quietlySaid(place, opened, found) {
|
|
15
|
+
const where = printable(place);
|
|
16
|
+
if (!found)
|
|
17
|
+
return `That conversation was not found here, so all conversations were ${opened ? 'opened' : 'written'}: ${where}\n`;
|
|
18
|
+
return opened ? `Opened: ${where}\n` : `Written: ${where}\n`;
|
|
19
|
+
}
|
|
7
20
|
/**
|
|
8
21
|
* Everything `start` says about one run: the wordmark, then what the range needs, then where the page is. The
|
|
9
22
|
* sentences are the ones this command has always printed - the heading and the indent are what group them, so a
|
|
@@ -59,9 +72,15 @@ function page(said, view) {
|
|
|
59
72
|
`${dim('Serving the page at', view)} ${bold(said.url, view)}`,
|
|
60
73
|
dim('A mark made on it is recorded at once. It stops after 30 minutes with no request, or with Ctrl+C.', view),
|
|
61
74
|
]),
|
|
62
|
-
...(said.welcome ===
|
|
75
|
+
...(said.welcome === 'opened' ? [`Opened the welcome page, to set agentwhy up for ${said.project ?? 'this project'}.`] : []),
|
|
76
|
+
...(said.welcome === 'served' ? [`That address opens the welcome page, to set agentwhy up for ${said.project ?? 'this project'}.`] : []),
|
|
63
77
|
...(said.servedAsFile === true
|
|
64
|
-
? [
|
|
78
|
+
? [
|
|
79
|
+
warn('The page could not be served, so it was opened as a file: marks made on it are copied as commands.', view),
|
|
80
|
+
// PF4's way out, which `--detach` has always said and this run did not: a sandbox is the usual reason, and a
|
|
81
|
+
// person reading a file cannot finish a setup or make a mark on it.
|
|
82
|
+
dim('To open it live, run this command again outside the sandbox, or type npx @agentwhy/cli in a terminal.', view),
|
|
83
|
+
]
|
|
65
84
|
: []),
|
|
66
85
|
dim(said.shared
|
|
67
86
|
? 'Shared view: session ids and the project path are not shown, and nothing above the project root appears in any report.'
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { ALERT_THRESHOLDS } from '../../watch/agent-alert.js';
|
|
2
4
|
import { CLEAN_MODES, NOTICE_CHANNELS, NOTICE_LANGS, SAID_AS } from '../../watch/notice-choices.js';
|
|
3
5
|
import { isMarkResult, MARK_RESULTS } from '../../../ports/mark-store.js';
|
|
@@ -257,7 +259,8 @@ function settingsChange(fields) {
|
|
|
257
259
|
}
|
|
258
260
|
if (Object.keys(rules).length === 0)
|
|
259
261
|
return 'An uninstall names the files it takes agentwhy out of.';
|
|
260
|
-
|
|
262
|
+
// AO17: the window's unticked choice - out of the person's own Codex files too. Anything but true is unticked.
|
|
263
|
+
return { change: 'uninstall', rules, ...(fields.codex === true ? { codex: true } : {}) };
|
|
261
264
|
}
|
|
262
265
|
// The same rule, in the other file. `where` is the destination and is required here: a move with no file named
|
|
263
266
|
// is not a move. A hook is moved by a `hooks` change instead, which names the file it is to run from.
|
|
@@ -112,6 +112,16 @@ async function uninstall(setup, change) {
|
|
|
112
112
|
return { outcome: out.outcome, output: said.filter(Boolean).join('\n') };
|
|
113
113
|
written ||= out.outcome === 'written';
|
|
114
114
|
}
|
|
115
|
+
// AO17, ticked: agentwhy's check and its approvals out of the person's own Codex files too, after the project's part.
|
|
116
|
+
// `hooks: []` is the empty set, not silence: this run is Codex's alone, and the files the window named were already
|
|
117
|
+
// done above. Naming the two hooks here would take them out of the local file as well, which no tick asked for.
|
|
118
|
+
if (change.codex === true) {
|
|
119
|
+
const out = await setup.run({ protect: [], remove: true, yes: true, codex: true, hooks: [] });
|
|
120
|
+
said.push(out.output.trim());
|
|
121
|
+
if (out.outcome !== 'written' && out.outcome !== 'unchanged')
|
|
122
|
+
return { outcome: out.outcome, output: said.filter(Boolean).join('\n') };
|
|
123
|
+
written ||= out.outcome === 'written';
|
|
124
|
+
}
|
|
115
125
|
return { outcome: written ? 'written' : 'unchanged', output: said.filter(Boolean).join('\n') };
|
|
116
126
|
}
|
|
117
127
|
/**
|