@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,5 +1,5 @@
|
|
|
1
1
|
import { isJsonObject } from '../../../shared/json.js';
|
|
2
|
-
import { isKnownDenialKind, RULE_REFUSED_READ, RULE_REFUSED_READ_KIND } from '../contract/denials.js';
|
|
2
|
+
import { DENIAL_SOURCE, isKnownDenialKind, RULE_REFUSED_READ, RULE_REFUSED_READ_KIND } from '../contract/denials.js';
|
|
3
3
|
import { AGENT_TOOL, HANDBACK_TOOL, FIELDS, TEXT_BLOCK_TYPE, THINKING_BLOCK_TYPE, TOOL_RESULT_BLOCK_TYPE } from '../contract/fields.js';
|
|
4
4
|
import { ASSISTANT_LINE_TYPE, USER_LINE_TYPE } from '../contract/line-types.js';
|
|
5
5
|
import { toolResultReferences } from '../contract/layout.js';
|
|
@@ -121,9 +121,10 @@ export function delegationTextIn(call) {
|
|
|
121
121
|
export function resultsIn(record) {
|
|
122
122
|
const payload = record[FIELDS.toolUseResult];
|
|
123
123
|
const denialValue = record[FIELDS.denialKind];
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
:
|
|
124
|
+
// A value the contract knows says who refused (WS1); any other names nobody, and stays unknown.
|
|
125
|
+
const denial = typeof denialValue !== 'string' ? undefined
|
|
126
|
+
: isKnownDenialKind(denialValue) ? { kind: denialValue, recognised: true, source: DENIAL_SOURCE[denialValue] }
|
|
127
|
+
: { kind: denialValue, recognised: false };
|
|
127
128
|
const blocks = contentBlocks(record).filter((block) => block[FIELDS.blockType] === TOOL_RESULT_BLOCK_TYPE);
|
|
128
129
|
// The marker sits on the record, not on a block, so it names a call only while the record holds exactly one.
|
|
129
130
|
const attributable = blocks.length === 1;
|
|
@@ -143,7 +144,7 @@ export function resultsIn(record) {
|
|
|
143
144
|
...(denial !== undefined && attributable
|
|
144
145
|
? { denial }
|
|
145
146
|
: refusedByRule
|
|
146
|
-
? { denial: { kind: RULE_REFUSED_READ_KIND, recognised: true } }
|
|
147
|
+
? { denial: { kind: RULE_REFUSED_READ_KIND, recognised: true, source: DENIAL_SOURCE[RULE_REFUSED_READ_KIND] } }
|
|
147
148
|
: {}),
|
|
148
149
|
...(launched && attributable ? { launchNotice: true } : {}),
|
|
149
150
|
spilledFiles: spilledFilesIn(block[FIELDS.blockContent], payload),
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { HOOK_OUTPUT, TERMINAL } from '../contract/hooks.js';
|
|
2
4
|
/** C0 and C1 control characters, and DEL: any of them in the words would take the sequence outside the allowlist. */
|
|
3
5
|
const CONTROL = /[\u0000-\u001f\u007f-\u009f]/g;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { SUBAGENT_STOP } from '../contract/hooks.js';
|
|
2
4
|
import { parseJsonObject } from '../../../shared/json.js';
|
|
3
5
|
/** Reads the text a hook was given on standard input. Never throws: an input it cannot use is a named answer. */
|
|
@@ -15,12 +17,14 @@ export function parseSubagentStopInput(text) {
|
|
|
15
17
|
}
|
|
16
18
|
const lastMessage = input[fields.lastMessage];
|
|
17
19
|
const sessionId = input[fields.sessionId];
|
|
20
|
+
const agentTranscriptPath = input[fields.agentTranscriptPath];
|
|
18
21
|
return {
|
|
19
22
|
agent: {
|
|
20
23
|
transcriptPath,
|
|
21
24
|
agentId,
|
|
22
25
|
...(typeof lastMessage === 'string' ? { lastMessage } : {}),
|
|
23
26
|
...(typeof sessionId === 'string' && sessionId !== '' ? { sessionId } : {}),
|
|
27
|
+
...(typeof agentTranscriptPath === 'string' && agentTranscriptPath !== '' ? { agentTranscriptPath } : {}),
|
|
24
28
|
},
|
|
25
29
|
};
|
|
26
30
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
2
4
|
import { toLabel } from '../../../shared/label.js';
|
|
3
5
|
import { CONTRACT_VERSION, VERIFIED_AGAINST } from '../contract/version.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { AGENT_TOOL, FIELDS } from '../../contract/fields.js';
|
|
2
4
|
import { USER_LINE_TYPE } from '../../contract/line-types.js';
|
|
3
5
|
import { notificationsIn } from '../../contract/task-notifications.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { FIELDS, TOOL_RESULT_BLOCK_TYPE } from '../../contract/fields.js';
|
|
2
4
|
import { toolResultReferences } from '../../contract/layout.js';
|
|
3
5
|
import { contentBlocks } from '../transcript-line.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { isJsonObject } from '../../../shared/json.js';
|
|
2
4
|
import { FIELDS, TEXT_BLOCK_TYPE, TOOL_RESULT_BLOCK_TYPE, TOOL_USE_BLOCK_TYPE } from '../contract/fields.js';
|
|
3
5
|
export function contentBlocks(line) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { parseJsonObject } from '../../../shared/json.js';
|
|
2
4
|
import { DeniedCallCollector } from './collectors/denied-call-collector.js';
|
|
3
5
|
import { IdentifierCollector } from './collectors/identifier-collector.js';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { isJsonObject } from '../../../shared/json.js';
|
|
2
4
|
import { PACKAGE } from '../../../shared/package-name.js';
|
|
3
5
|
import { isPlainInvocation, NPX_BEFORE_NAME, VERSION } from '../../../shared/plain-invocation.js';
|
|
@@ -75,6 +77,13 @@ function runningEvents(settings, invoke) {
|
|
|
75
77
|
* Which of agentwhy's hooks a settings object already runs (R8): through any command naming agentwhy, and through
|
|
76
78
|
* `invoke`, the invocation this run of `init` was given, however it is spelled.
|
|
77
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* The full command these settings run `refuse` with, whose own flags name the rules it reads
|
|
82
|
+
* (`2026-10-02-codex-approves-its-own-hook.md` AO5, AO6).
|
|
83
|
+
*/
|
|
84
|
+
export function refuseCommandIn(settings) {
|
|
85
|
+
return commandsIn(settings).find((command) => hookRun(command, undefined) === 'refuse');
|
|
86
|
+
}
|
|
78
87
|
export function installedHooks(settings, invoke) {
|
|
79
88
|
const found = new Set();
|
|
80
89
|
for (const command of commandsIn(settings)) {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { dirname, isAbsolute, join } from 'node:path';
|
|
4
|
+
import { FileAccessError } from '../../../ports/file-access-error.js';
|
|
5
|
+
import { parseJsonObject } from '../../../shared/json.js';
|
|
6
|
+
import { SETTINGS_FILES } from '../contract/settings.js';
|
|
7
|
+
import { refuseCommandIn } from './hook-entries.js';
|
|
8
|
+
/** How far up from where a hook ran a project is looked for. */
|
|
9
|
+
const MOST_FOLDERS_UP = 64;
|
|
10
|
+
/**
|
|
11
|
+
* `2026-10-02-codex-approves-its-own-hook.md` AO5: the project for a Codex command or turn is the nearest folder, at or
|
|
12
|
+
* above `folder`, whose `.claude/settings.local.json` or `settings.json` runs agentwhy's `refuse` - the local file
|
|
13
|
+
* first, as `init` reads them. Codex runs agentwhy's check in the session's folder, which can lie below the project and
|
|
14
|
+
* names it nowhere (CKB6); the rules that block there are the project's own, so the project is the folder that holds
|
|
15
|
+
* them. A folder with a `.claude` of its own and no `refuse` does not stop the walk.
|
|
16
|
+
*
|
|
17
|
+
* The walk ends at the home directory, which is never a project (`which-project` V8; `codex-says-it-too` CXB6): a
|
|
18
|
+
* `refuse` in the person's own `~/.claude/settings.json` would otherwise make every folder under home a project. One
|
|
19
|
+
* lookup for `refuse --codex`, the turn's rules (CX5) and whether a turn is watched (CX9), so the three never disagree.
|
|
20
|
+
*/
|
|
21
|
+
export async function refuseProjectAbove(files, folder, home) {
|
|
22
|
+
for (let at = folder, depth = 0; depth < MOST_FOLDERS_UP; depth += 1) {
|
|
23
|
+
if (at === home)
|
|
24
|
+
return undefined;
|
|
25
|
+
for (const file of [SETTINGS_FILES.local, SETTINGS_FILES.shared]) {
|
|
26
|
+
const settingsPath = join(at, SETTINGS_FILES.directory, file);
|
|
27
|
+
const settings = parseJsonObject((await textOf(files, settingsPath)) ?? '');
|
|
28
|
+
const command = settings === undefined ? undefined : refuseCommandIn(settings);
|
|
29
|
+
if (command !== undefined)
|
|
30
|
+
return { project: at, settingsPath, command };
|
|
31
|
+
}
|
|
32
|
+
const up = dirname(at);
|
|
33
|
+
if (up === at)
|
|
34
|
+
return undefined;
|
|
35
|
+
at = up;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const PROJECT_DIR = /^\$(?:\{CLAUDE_PROJECT_DIR\}|CLAUDE_PROJECT_DIR)/;
|
|
40
|
+
/**
|
|
41
|
+
* One whole shell word, as a shell reads the value of a flag: quoted parts, escapes and bare characters joined into a
|
|
42
|
+
* single path. A command quotes only the part it has to - `--settings "$CLAUDE_PROJECT_DIR"/.claude/settings.json` -
|
|
43
|
+
* and reading the first quoted part alone would name the project's folder as the file to read.
|
|
44
|
+
*/
|
|
45
|
+
const WORD = '(?:"(?:[^"\\\\]|\\\\.)*"|\'[^\']*\'|\\\\.|[^\\s"\'])+';
|
|
46
|
+
const SETTINGS_FLAG = new RegExp(`\\s--settings(?:\\s+|=)(${WORD})`);
|
|
47
|
+
const POLICY_FLAG = new RegExp(`\\s--policy(?:\\s+|=)(${WORD})`);
|
|
48
|
+
/**
|
|
49
|
+
* AO6: the rules the project's `refuse` reads, as its own command names them - a policy file, else a settings file,
|
|
50
|
+
* `$CLAUDE_PROJECT_DIR` and a relative path resolved against the project - or neither, which is the built-in list.
|
|
51
|
+
*/
|
|
52
|
+
export function refuseRulesOf(found) {
|
|
53
|
+
const policy = flagValue(found, POLICY_FLAG);
|
|
54
|
+
if (policy !== undefined)
|
|
55
|
+
return { policyPath: policy };
|
|
56
|
+
const settings = flagValue(found, SETTINGS_FLAG);
|
|
57
|
+
return settings === undefined ? {} : { settingsPath: settings };
|
|
58
|
+
}
|
|
59
|
+
function flagValue(found, flag) {
|
|
60
|
+
const word = flag.exec(found.command)?.[1];
|
|
61
|
+
if (word === undefined)
|
|
62
|
+
return undefined;
|
|
63
|
+
const raw = unquoted(word);
|
|
64
|
+
const resolved = PROJECT_DIR.test(raw) ? join(found.project, raw.replace(PROJECT_DIR, '.')) : raw;
|
|
65
|
+
return isAbsolute(resolved) ? resolved : join(found.project, resolved);
|
|
66
|
+
}
|
|
67
|
+
/** The word as the shell hands it to `refuse`: its quotes taken off and its `\` escapes resolved. */
|
|
68
|
+
function unquoted(word) {
|
|
69
|
+
let out = '';
|
|
70
|
+
let quote;
|
|
71
|
+
for (let at = 0; at < word.length; at += 1) {
|
|
72
|
+
const char = word[at];
|
|
73
|
+
if (quote !== '\'' && char === '\\' && at + 1 < word.length) {
|
|
74
|
+
out += word[at + 1];
|
|
75
|
+
at += 1;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (quote === undefined && (char === '"' || char === '\'')) {
|
|
79
|
+
quote = char;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (char === quote) {
|
|
83
|
+
quote = undefined;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
out += char;
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
async function textOf(files, path) {
|
|
91
|
+
try {
|
|
92
|
+
return await files.readText(path);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error instanceof FileAccessError)
|
|
96
|
+
return undefined;
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* What an agent's code did, as `event_msg/item_completed` records it: one typed item per action, joined to its turn by
|
|
3
5
|
* `turn_id` and to its agent by `thread_id` in every measured item (§2.3, 2,344 items; §2.8, 33). An item holds both what
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { isAbsolute, join, relative, sep } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Where the ChatGPT desktop app runs a chat that has no project: a folder it makes under the home directory, named after
|
|
6
|
+
* the day and the chat (`.ai/specs/2026-09-30-run-from-another-app.md` OAB5). Measured 2026-10-01: the recorded `cwd` of
|
|
7
|
+
* 7 of 153 rollouts, written by `originator` `codex_work_desktop` with `thread_source` `chatgpt_handoff`, was
|
|
8
|
+
* `~/Documents/Codex/<YYYY-MM-DD>/<chat>`. Other systems, and other versions of the app, are not measured.
|
|
9
|
+
*/
|
|
10
|
+
const CHAT_ROOT = ['Documents', 'Codex'];
|
|
11
|
+
const DAY = /^\d{4}-\d{2}-\d{2}$/;
|
|
12
|
+
/** Whether a folder is one the ChatGPT app made for a chat with no project: no project of the person's (V10b). */
|
|
13
|
+
export function inChatFolder(path, home) {
|
|
14
|
+
const between = relative(join(home, ...CHAT_ROOT), path);
|
|
15
|
+
if (between === '' || isAbsolute(between) || between.startsWith('..'))
|
|
16
|
+
return false;
|
|
17
|
+
const [day, chat] = between.split(sep);
|
|
18
|
+
return day !== undefined && DAY.test(day) && chat !== undefined && chat !== '';
|
|
19
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* An agent the agent chose to start, and what it said to it later (X15-X18; §2.4). Measured on one delegation only
|
|
3
5
|
* (§2.4, §2.7): every join here is by id and leaves the relation unresolved where it breaks. XB4 remains open, so these
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* What the model is handed (XB5, §2.8). The model writes JavaScript into the `exec` tool; the cell's own output,
|
|
3
5
|
* `custom_tool_call_output.output`, is the one thing of it the model receives - a string, or parts whose text is under
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* The line envelope: `{timestamp, type, payload}`, with `ordinal` on most lines (spec §2.1, 66 files; §2.7, 70; §2.8, 7).
|
|
3
5
|
* Only top-level lines are records (X13): a `compacted` line's nested copies are none.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* A command a `PreToolUse` hook refused (`codex-blocks-too` CKB3, CKB7, CKB11): it never runs, so no item records it, and
|
|
3
5
|
* the one trace is text in the code cell's output - "Script error:\nCommand blocked by PreToolUse hook: <reason>.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* A project's Codex hooks (`specs/2026-09-30-codex-blocks-too.md` CKB4): `<project>/.codex/hooks.json`, in the shape
|
|
3
5
|
* `{"hooks": {"PreToolUse": [{"matcher": "Bash", "hooks": [{"type": "command", "command": "…"}]}]}}`. Measured on 0.159.2:
|
|
@@ -34,7 +36,11 @@ export const PRE_TOOL_USE = {
|
|
|
34
36
|
/** The shell tool, and the matcher a hook for it is written with. */
|
|
35
37
|
shellTool: 'Bash',
|
|
36
38
|
};
|
|
37
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* A completed Codex turn, measured with `codex exec` 0.159.2. Its transcript path can be absent (ephemeral runs).
|
|
41
|
+
* `session_id`, `cwd` and `last_assistant_message` are documented beside the measured ones (`the-agent-tells-you` D18)
|
|
42
|
+
* and read where present: what `watch` says at the end of a Codex turn (`2026-10-02-codex-says-it-too.md` CX1).
|
|
43
|
+
*/
|
|
38
44
|
export const STOP = {
|
|
39
45
|
event: 'Stop',
|
|
40
46
|
fields: {
|
|
@@ -42,5 +48,49 @@ export const STOP = {
|
|
|
42
48
|
active: 'stop_hook_active',
|
|
43
49
|
turnId: 'turn_id',
|
|
44
50
|
transcriptPath: 'transcript_path',
|
|
51
|
+
sessionId: 'session_id',
|
|
52
|
+
workingDirectory: 'cwd',
|
|
53
|
+
lastMessage: 'last_assistant_message',
|
|
45
54
|
},
|
|
46
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* The person's own Codex hooks and their approval (`2026-10-02-codex-approves-its-own-hook.md` AOB1, measured
|
|
58
|
+
* 2026-10-02 on 0.159.3 and the VS Code extension's bundled 0.159.2): `~/.codex/hooks.json` has the project file's
|
|
59
|
+
* shape and belongs to Codex's user layer, read in every folder, trusted or not. A hook in it runs only with a matching
|
|
60
|
+
* approval in `~/.codex/config.toml`: a table
|
|
61
|
+
* `[hooks.state."<absolute path of hooks.json>:<event in snake case>:<group index>:<handler index>"]` whose
|
|
62
|
+
* `trusted_hash` equals the entry's current hash. The key is positional: an entry added or removed above another's
|
|
63
|
+
* shifts the keys below it (AOD3).
|
|
64
|
+
*/
|
|
65
|
+
export const USER_HOOKS = {
|
|
66
|
+
/** Under the home directory, beside the sessions root (`session.ts` CODEX_FOLDER). */
|
|
67
|
+
directory: '.codex',
|
|
68
|
+
file: 'hooks.json',
|
|
69
|
+
config: 'config.toml',
|
|
70
|
+
/** The keys of the table agentwhy reads and writes, under `hooks.state`. */
|
|
71
|
+
trustedHash: 'trusted_hash',
|
|
72
|
+
enabled: 'enabled',
|
|
73
|
+
/**
|
|
74
|
+
* How long Codex waits for agentwhy's check, named in each entry (AOD9): Codex's own default is 600 seconds (AOB8),
|
|
75
|
+
* which a hanging `npx` would hold every command for. Hashed as AOB10 measured.
|
|
76
|
+
*/
|
|
77
|
+
timeoutSeconds: 30,
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* The hash Codex checks an approval against (AOB1): `sha256:` + SHA-256, hex, over compact JSON with keys sorted at
|
|
81
|
+
* every depth, of `{"event_name": <snake case>, "matcher": <the group's, omitted when none>, "hooks": [entry]}`, where
|
|
82
|
+
* the entry is `{"type": "command", "command": <as written>, "timeout": <600 unless the file names one, and at least
|
|
83
|
+
* 1>, "async": <false unless named>}` - the defaults written in, `statusMessage` only where the file names it, and
|
|
84
|
+
* `commandWindows` never (Codex normalizes it away before hashing). A `Stop` group's matcher is dropped before
|
|
85
|
+
* hashing; `PreToolUse` keeps its own (`matcher_pattern_for_event`). Events in snake case: `PreToolUse` is
|
|
86
|
+
* `pre_tool_use`, `Stop` is `stop`.
|
|
87
|
+
*/
|
|
88
|
+
export const HOOK_HASH = {
|
|
89
|
+
prefix: 'sha256:',
|
|
90
|
+
defaultTimeout: 600,
|
|
91
|
+
eventKeys: { PreToolUse: 'pre_tool_use', Stop: 'stop' },
|
|
92
|
+
/** The entry fields the hash reads, by the names the file uses. */
|
|
93
|
+
fields: { timeout: 'timeout', async: 'async', statusMessage: 'statusMessage' },
|
|
94
|
+
/** A field Codex hashes on context-emitting events, which the recipe was not measured over (AO2). */
|
|
95
|
+
unmeasured: ['additionalContextLimit'],
|
|
96
|
+
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* The agent's own words and the words it was given (X31; XB10, §2.8). Measured for `codex exec` 0.157.0 `paginated`:
|
|
3
5
|
* assistant text is `response_item/message` with role `assistant`, content `output_text` and a `phase`; an `AgentMessage`
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* The runtime permissions a `turn_context` records for its turn (§2.5; §2.8): recorded settings, never agentwhy's policy
|
|
3
5
|
* and never a verdict on a path (X21, X22). Values outside these lists are kept out of the model and said as unknown.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* Codex's own reviewer (X19, X20; §2.4): a child thread whose `source.subagent.other` is `guardian`, started by Codex and
|
|
3
5
|
* never by the agent. Its turns name the reviewed turn by `root_turn_id` (§2.7: 52 references, all present); its
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/** First-line discovery (§2.1, §2.7). Measured 2026-09-29; action and message semantics have separate gates. */
|
|
2
4
|
export const SESSION = {
|
|
3
5
|
lineType: 'type',
|
|
@@ -11,11 +13,35 @@ export const SESSION = {
|
|
|
11
13
|
version: 'cli_version',
|
|
12
14
|
/** A string for a person's session (`exec` in §2.8); an object `{subagent: …}` for a thread another started (§2.4). */
|
|
13
15
|
source: 'source',
|
|
16
|
+
/** Which Codex app wrote the file: `codex-tui`, `codex_vscode`, `Codex Desktop`, `codex_work_desktop`, `codex_exec` (CXB3). */
|
|
17
|
+
originator: 'originator',
|
|
14
18
|
filePrefix: 'rollout-',
|
|
15
19
|
fileSuffix: '.jsonl',
|
|
16
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* Codex's own folder, under the home directory: where its terminal app, its VS Code extension and the desktop app keep
|
|
23
|
+
* their conversations (X1; `run-from-another-app` OAB4, OAB5). There, Codex is used on this computer (`codex-blocks-too`
|
|
24
|
+
* CK6). `$CODEX_HOME` is not measured (XB6).
|
|
25
|
+
*/
|
|
26
|
+
export const CODEX_FOLDER = ['.codex'];
|
|
17
27
|
/** Where Codex keeps its rollouts, under the home directory (X1, §2.1). `$CODEX_HOME` is not measured (XB6). */
|
|
18
|
-
export const SESSIONS_ROOT = [
|
|
28
|
+
export const SESSIONS_ROOT = [...CODEX_FOLDER, 'sessions'];
|
|
29
|
+
/**
|
|
30
|
+
* Who is reading a conversation, by its first line (`2026-10-02-codex-says-it-too.md` CXB3). Over 175 rollouts of
|
|
31
|
+
* 2026-10-02: every conversation a person held - in the terminal, VS Code, the Codex app and the ChatGPT app - had the
|
|
32
|
+
* `source` `vscode` (139); a scripted run `exec` (32); a thread another started an object (32). The terminal app is the
|
|
33
|
+
* one whose `originator` is `codex-tui`.
|
|
34
|
+
*/
|
|
35
|
+
export const READER = {
|
|
36
|
+
personSource: 'vscode',
|
|
37
|
+
terminalOriginator: 'codex-tui',
|
|
38
|
+
/**
|
|
39
|
+
* The desktop app's names (its plain and work builds). Measured 2026-10-02 on the maintainer's conversations: with
|
|
40
|
+
* a Stop block, the desktop app folds everything before the bubble into its "Worked for ..." row - a control run
|
|
41
|
+
* without agentwhy showed the same answer in the open - while VS Code's Codex folds nothing (CXB5's display note).
|
|
42
|
+
*/
|
|
43
|
+
desktopOriginators: ['Codex Desktop', 'codex_work_desktop'],
|
|
44
|
+
};
|
|
19
45
|
export const HISTORY_MODES = ['paginated', 'legacy'];
|
|
20
46
|
/**
|
|
21
47
|
* Codex's own list of thread names, under the home directory: one JSON object a line, `{"id", "thread_name",
|
|
@@ -28,4 +54,6 @@ export const THREAD_NAMES = {
|
|
|
28
54
|
file: ['.codex', 'session_index.jsonl'],
|
|
29
55
|
id: 'id',
|
|
30
56
|
name: 'thread_name',
|
|
57
|
+
/** When the line was written, ISO: a thread's earliest line is its first session (CXB5). */
|
|
58
|
+
updatedAt: 'updated_at',
|
|
31
59
|
};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* A turn and its boundaries (§2.2): `turn_context` opens one per turn with its `turn_id`; `task_started`,
|
|
3
5
|
* `task_complete` and `turn_aborted` name it by the same id. Every item and response record carries it (§2.2, §2.8).
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* v1 (2026-09-29): first-line recognition and identity only, X1-X5, measured on 70 frozen files (spec §2.7).
|
|
3
5
|
* v2 (2026-09-29): the records a report reads - turns and their permissions, action items, messages, the cell's output
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { isDirectory } from '../../../ports/directory-reader.js';
|
|
5
|
+
import { CODEX_FOLDER } from '../contract/session.js';
|
|
6
|
+
/**
|
|
7
|
+
* `codex-blocks-too` CK6, amended 2026-10-01: Codex is used on this computer where its own folder is in the home
|
|
8
|
+
* directory. A project set up before its first conversation has none to tell which AI will work in it; the computer
|
|
9
|
+
* does. A folder that cannot be looked at is not taken as Codex.
|
|
10
|
+
*/
|
|
11
|
+
export async function codexOnThisComputer(directories, home) {
|
|
12
|
+
return isDirectory(directories, join(home, ...CODEX_FOLDER));
|
|
13
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isDirectory } from '../../../ports/directory-reader.js';
|
|
2
2
|
import { conversationsIn } from './codex-conversations.js';
|
|
3
3
|
/**
|
|
4
4
|
* The projects Codex keeps conversations for (`which-project.md` V9; X4): one per recorded `cwd` of a conversation's
|
|
@@ -30,20 +30,10 @@ export class CodexProjectCatalogue {
|
|
|
30
30
|
const projects = await Promise.all([...byFolder].map(async ([path, folder]) => ({
|
|
31
31
|
id: projectId(path),
|
|
32
32
|
path,
|
|
33
|
-
|
|
33
|
+
folder: this.#dependencies.leaveAlone?.(path) === true ? 'not-looked' : (await isDirectory(this.#dependencies.directories, path)) ? 'there' : 'gone',
|
|
34
34
|
conversations: folder.conversations,
|
|
35
35
|
newest: { modifiedAt: folder.newest },
|
|
36
36
|
})));
|
|
37
37
|
return { projects: projects.sort((a, b) => b.newest.modifiedAt - a.newest.modifiedAt), unreadable };
|
|
38
38
|
}
|
|
39
|
-
async #isDirectory(path) {
|
|
40
|
-
try {
|
|
41
|
-
return (await this.#dependencies.directories.kindOf(path)) === 'directory';
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
if (!(error instanceof FileAccessError))
|
|
45
|
-
throw error;
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
39
|
}
|
|
@@ -23,6 +23,7 @@ export class CodexSessionCatalogue {
|
|
|
23
23
|
provider: 'codex',
|
|
24
24
|
}))
|
|
25
25
|
.sort((a, b) => b.modifiedAt - a.modifiedAt);
|
|
26
|
-
|
|
26
|
+
// The place searched is Codex's whole store, so not finding it is the store missing (R28, amended 2026-10-01).
|
|
27
|
+
return { directory: sessionsRoot, found, searched: [{ provider: 'codex', directory: sessionsRoot, found, ...(found ? {} : { store: 'missing' }) }], sessions };
|
|
27
28
|
}
|
|
28
29
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/** An id owned by multiple files must resolve to none, regardless of traversal order (X3). */
|
|
2
4
|
export const AMBIGUOUS = Symbol('held by more than one file');
|
|
3
5
|
/** Used by runtime discovery and the reconnaissance probe, so they cannot choose different owners. */
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Copyright 2026 Nessprim Karol Kozer
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
import { basename } from 'node:path';
|
|
2
4
|
import { isJsonObject } from '../../../shared/json.js';
|
|
3
5
|
import { ACTION_ITEMS, CHANGE_KINDS, COMMAND, FILE_CHANGE, IMAGE_VIEW, ITEM, ITEM_STATUSES, MCP, OMISSION_NOTICE, SHELL_FLAGS, SHELLS, WEB_SEARCH, } from '../contract/actions.js';
|