aptly 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +23 -5
- package/README.ja.md +23 -5
- package/README.md +23 -5
- package/README.zh-CN.md +23 -5
- package/dist/bin/aptly.js +85 -7
- package/dist/src/cli-input.d.ts +5 -0
- package/dist/src/cli-input.js +49 -0
- package/dist/src/core.d.ts +1 -0
- package/dist/src/core.js +24 -9
- package/dist/src/credential-setup.d.ts +18 -0
- package/dist/src/credential-setup.js +89 -0
- package/dist/src/files.js +10 -3
- package/dist/src/ledger-lock.d.ts +8 -0
- package/dist/src/ledger-lock.js +153 -0
- package/dist/src/provider.js +13 -4
- package/dist/src/runtime.d.ts +5 -1
- package/dist/src/runtime.js +19 -3
- package/dist/src/secret-store.d.ts +27 -0
- package/dist/src/secret-store.js +263 -0
- package/dist/src/server.js +2 -1
- package/dist/src/setup.d.ts +14 -0
- package/dist/src/setup.js +297 -29
- package/dist/src/types.d.ts +4 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/windows-powershell.d.ts +2 -0
- package/dist/src/windows-powershell.js +11 -0
- package/dist/src/windows-private.d.ts +11 -0
- package/dist/src/windows-private.js +98 -0
- package/docs/guide/en.md +148 -15
- package/docs/guide/ja.md +148 -15
- package/docs/guide/ko.md +148 -15
- package/docs/guide/zh-CN.md +148 -15
- package/package.json +3 -2
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { windowsPowerShellPath } from './windows-powershell.js';
|
|
3
|
+
// Static code only: paths are JSON on stdin, never PowerShell source/arguments.
|
|
4
|
+
// Windows PowerShell's .NET Framework ACL APIs keep inherited ACEs visible.
|
|
5
|
+
const script = String.raw `
|
|
6
|
+
$ErrorActionPreference = 'Stop'
|
|
7
|
+
[Console]::InputEncoding = [Text.UTF8Encoding]::new($false)
|
|
8
|
+
try {
|
|
9
|
+
$request = [Console]::In.ReadToEnd() | ConvertFrom-Json
|
|
10
|
+
$path = [string]$request.path
|
|
11
|
+
if ([string]::IsNullOrWhiteSpace($path) -or ![IO.Path]::IsPathRooted($path)) { throw 'invalid' }
|
|
12
|
+
$attributes = [IO.File]::GetAttributes($path)
|
|
13
|
+
if (($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'invalid' }
|
|
14
|
+
$isDirectory = ($attributes -band [IO.FileAttributes]::Directory) -ne 0
|
|
15
|
+
$sidType = [Security.Principal.SecurityIdentifier]
|
|
16
|
+
$current = [Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
17
|
+
$allowed = @($current.Value, 'S-1-5-18', 'S-1-5-32-544')
|
|
18
|
+
if ($request.action -eq 'protect-new-directory') {
|
|
19
|
+
if (!$isDirectory) { throw 'invalid' }
|
|
20
|
+
$acl = [Security.AccessControl.DirectorySecurity]::new()
|
|
21
|
+
$acl.SetOwner($current)
|
|
22
|
+
$acl.SetAccessRuleProtection($true, $false)
|
|
23
|
+
foreach ($sid in $allowed) {
|
|
24
|
+
$identity = [Security.Principal.SecurityIdentifier]::new($sid)
|
|
25
|
+
$rule = [Security.AccessControl.FileSystemAccessRule]::new($identity, [Security.AccessControl.FileSystemRights]::FullControl, ([Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [Security.AccessControl.InheritanceFlags]::ObjectInherit), [Security.AccessControl.PropagationFlags]::None, [Security.AccessControl.AccessControlType]::Allow)
|
|
26
|
+
$acl.AddAccessRule($rule)
|
|
27
|
+
}
|
|
28
|
+
[IO.Directory]::SetAccessControl($path, $acl)
|
|
29
|
+
} elseif ($request.action -ne 'assert-private') { throw 'invalid' }
|
|
30
|
+
$acl = if ($isDirectory) { [IO.Directory]::GetAccessControl($path) } else { [IO.File]::GetAccessControl($path) }
|
|
31
|
+
if ($allowed -notcontains $acl.GetOwner($sidType).Value) { throw 'invalid' }
|
|
32
|
+
$descriptor = [Security.AccessControl.RawSecurityDescriptor]::new($acl.GetSecurityDescriptorBinaryForm(), 0)
|
|
33
|
+
if ($null -eq $descriptor.DiscretionaryAcl) { throw 'invalid' }
|
|
34
|
+
foreach ($rule in $acl.GetAccessRules($true, $true, $sidType)) {
|
|
35
|
+
if ($rule.AccessControlType -eq [Security.AccessControl.AccessControlType]::Allow -and $allowed -notcontains $rule.IdentityReference.Value) { throw 'invalid' }
|
|
36
|
+
}
|
|
37
|
+
[Console]::Out.Write('private')
|
|
38
|
+
} catch { [Console]::Out.Write('rejected'); exit 1 }
|
|
39
|
+
`;
|
|
40
|
+
const run = (executable, args, input) => execFileSync(executable, [...args], {
|
|
41
|
+
input, encoding: 'utf8', windowsHide: true, timeout: 10000, maxBuffer: 4096, stdio: ['pipe', 'pipe', 'pipe']
|
|
42
|
+
});
|
|
43
|
+
const copyScript = String.raw `
|
|
44
|
+
$ErrorActionPreference = 'Stop'
|
|
45
|
+
[Console]::InputEncoding = [Text.UTF8Encoding]::new($false)
|
|
46
|
+
try {
|
|
47
|
+
$request = [Console]::In.ReadToEnd() | ConvertFrom-Json
|
|
48
|
+
$source = [string]$request.source
|
|
49
|
+
$target = [string]$request.target
|
|
50
|
+
if (![IO.Path]::IsPathRooted($source) -or ![IO.Path]::IsPathRooted($target)) { throw 'invalid' }
|
|
51
|
+
$source = [IO.Path]::GetFullPath($source)
|
|
52
|
+
$target = [IO.Path]::GetFullPath($target)
|
|
53
|
+
if ([string]::Equals($source, $target, [StringComparison]::OrdinalIgnoreCase) -or ![string]::Equals([IO.Path]::GetDirectoryName($source), [IO.Path]::GetDirectoryName($target), [StringComparison]::OrdinalIgnoreCase)) { throw 'invalid' }
|
|
54
|
+
foreach ($path in @($source, $target)) {
|
|
55
|
+
$attributes = [IO.File]::GetAttributes($path)
|
|
56
|
+
if (($attributes -band [IO.FileAttributes]::Directory) -ne 0 -or ($attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'invalid' }
|
|
57
|
+
}
|
|
58
|
+
$sections = [Security.AccessControl.AccessControlSections]::Access
|
|
59
|
+
$sourceAcl = [IO.File]::GetAccessControl($source, $sections)
|
|
60
|
+
$expected = $sourceAcl.GetSecurityDescriptorSddlForm($sections)
|
|
61
|
+
$initial = [IO.File]::GetAccessControl($target, $sections).GetSecurityDescriptorSddlForm($sections)
|
|
62
|
+
# A sibling stage normally inherits the same ACL. Avoid reapplying inherited
|
|
63
|
+
# ACEs when the full DACL descriptor (including protection) already matches.
|
|
64
|
+
if ($expected -ceq $initial) { [Console]::Out.Write('private'); exit 0 }
|
|
65
|
+
$acl = [Security.AccessControl.FileSecurity]::new()
|
|
66
|
+
$acl.SetSecurityDescriptorSddlForm($expected, $sections)
|
|
67
|
+
[IO.File]::SetAccessControl($target, $acl)
|
|
68
|
+
$actual = [IO.File]::GetAccessControl($target, $sections).GetSecurityDescriptorSddlForm($sections)
|
|
69
|
+
if ($expected -cne $actual) { throw 'invalid' }
|
|
70
|
+
[Console]::Out.Write('private')
|
|
71
|
+
} catch { [Console]::Out.Write('rejected'); exit 1 }
|
|
72
|
+
`;
|
|
73
|
+
function runScript(scriptText, input, options) {
|
|
74
|
+
try {
|
|
75
|
+
const executable = windowsPowerShellPath();
|
|
76
|
+
const result = (options.execute ?? run)(executable, ['-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(scriptText, 'utf16le').toString('base64')], JSON.stringify(input));
|
|
77
|
+
if (result !== 'private')
|
|
78
|
+
throw new Error();
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
throw new Error('windows_private_permissions');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function invoke(path, action, options) {
|
|
85
|
+
if (typeof path !== 'string' || !path || path.includes('\0'))
|
|
86
|
+
throw new Error('windows_private_permissions');
|
|
87
|
+
runScript(script, { path, action }, options);
|
|
88
|
+
}
|
|
89
|
+
/** Preserve the existing file DACL, including inheritance protection, before writing stage content. */
|
|
90
|
+
export function copyWindowsFilePermissions(source, target, options = {}) {
|
|
91
|
+
if ([source, target].some(path => typeof path !== 'string' || !path || path.includes('\0')))
|
|
92
|
+
throw new Error('windows_private_permissions');
|
|
93
|
+
runScript(copyScript, { source, target }, options);
|
|
94
|
+
}
|
|
95
|
+
/** Existing paths are inspected, never repaired or granted new permissions. */
|
|
96
|
+
export function assertWindowsPrivatePath(path, options = {}) { invoke(path, 'assert-private', options); }
|
|
97
|
+
/** Only call immediately after this process exclusively created the directory. */
|
|
98
|
+
export function protectNewWindowsPrivateDirectory(path, options = {}) { invoke(path, 'protect-new-directory', options); }
|
package/docs/guide/en.md
CHANGED
|
@@ -4,47 +4,158 @@
|
|
|
4
4
|
|
|
5
5
|
[Back to README](../../README.en.md)
|
|
6
6
|
|
|
7
|
-
Korean is the canonical documentation. This guide covers
|
|
7
|
+
Korean is the canonical documentation. This guide covers general Aptly installation and usage. Package availability does not establish model access for every account. Claude Code or Codex controls native subagent execution, approvals, sandboxing, and MCP permissions.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Requires Node.js 24 or later and Claude Code or Codex. Install the latest stable npm release globally:
|
|
12
|
+
|
|
13
|
+
**Before upgrading an existing persistent ledger to 0.1.2 or later**, stop every host, MCP server, standalone CLI, and older process that can access it. The persistent gate cannot coexist with older writers. Fresh installations need no legacy-lock quarantine. If an old empty lock remains, follow the [ledger transition procedure](#interrupted-processes-and-ledger-locks): quarantine only a confirmed legacy lock while offline and preserve the JSON ledger, `unknown` records, costs, and completed cache.
|
|
12
14
|
|
|
13
15
|
```sh
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
npm install -g aptly@latest
|
|
17
|
+
aptly setup --client all --mode defaults
|
|
18
|
+
aptly --version
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
Use `aptly --version` to check the installed version. Switching Node.js environments may require reinstalling.
|
|
20
22
|
|
|
21
23
|
`postinstall` registers the MCP server and a `PreToolUse` Hook in the current user's existing host configuration directories. If you use `CODEX_HOME` or `CLAUDE_CONFIG_DIR`, pass the same environment to installation. Automatic registration skips host directories that do not exist; explicit `setup` can create them. To register only one host, use `--client codex` or `--client claude`.
|
|
22
24
|
|
|
23
25
|
New registrations set `ROUTER_PROVIDER=decisions`, the Hook's `defaults` policy, and a private ledger for each host. Other settings and Hooks, and existing Aptly commands, environments, providers, and ledger paths, are preserved. Existing fixture settings are not automatically switched to paid mode.
|
|
24
26
|
|
|
27
|
+
### Configure with the CLI
|
|
28
|
+
|
|
29
|
+
The `set` commands require 0.1.1 or later. Commands do not automatically switch existing launch paths. API-key setup accepts only the current package’s standard Node/server registration with a verified OS-source-compatible runtime. Custom wrappers, older versions, and other installation prefixes are rejected with `credential_launcher_unverified`; explicitly switch the registration or upgrade it before trying again.
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
aptly set default
|
|
33
|
+
aptly set env APTLY_CODEX_MODELS
|
|
34
|
+
aptly set env OPENAI_API_KEY
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The first command registers Claude Code and Codex and adds missing default environment settings. It preserves existing launch commands, environment whitelists, providers, custom candidates, and advisory policies. The second prompts for a value with hidden input and changes only the named variable. The third stores the API key in the OS credential store and connects it to the selected host at startup. Do not pass values as command arguments.
|
|
38
|
+
|
|
39
|
+
Both hosts are selected by default. Use `--client codex`, `--client claude`, or `--client all` to select targets. For example, enter a JSON string such as `["haiku","sonnet","opus"]` for Claude candidates.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
aptly set env APTLY_CLAUDE_MODELS --client claude
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Use explicit `--stdin` for automation. This is a public-variable example; never put a real key in a `printf` command or shell history.
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
printf '%s\n' '["gpt-6.1-terra"]' | aptly set env APTLY_CODEX_MODELS --stdin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Allowed public keys are `ROUTER_PROVIDER` (`fixture` or `decisions`), `APTLY_CLAUDE_MODELS`, `APTLY_CODEX_MODELS`, `CLAUDE_MODELS`, `CODEX_MODELS`, and `APTLY_MODEL_INFO_PATH`. Candidates must be JSON array strings of supported models. Invalid values, duplicates, and primary-name/alias conflicts are rejected. `[]` disables that host; a model-cache path must be absolute and inside a private directory. Managed ledger and Hook-policy paths cannot be changed through this command.
|
|
52
|
+
|
|
53
|
+
API keys are stored through macOS Keychain, an installed Linux `secret-tool`, or Windows Credential Manager. The Windows backend uses PowerShell and Win32 Generic credentials in the current-user scope, with a limit of 2,560 UTF-8 bytes. Windows CI verified synthetic key storage, lookup, update and deletion, Unicode paths, isolated host configuration, key references, and ACL preservation. It did not run actual Claude Code or Codex sessions on Windows. Unavailable credential stores return an error; there is no plaintext-file fallback. Keys use separate host accounts, while MCP files contain only `APTLY_SECRET_BACKEND=os` and `APTLY_SECRET_CLIENT` references. Once the OS source is selected, a missing or unreadable key does not silently fall back to another environment key. `set default` preserves existing wrapper/environment authentication; running `set env OPENAI_API_KEY` explicitly selects OS-store authentication.
|
|
54
|
+
|
|
55
|
+
Results contain host statuses and fixed error codes, never key values. Inspect each host when the result is `partial`. `credential_store_failed` requires checking store access/support; `credential_rollback_failed` requires checking whether the previous key was restored. A failed host restores its old key where possible. Do not interpret success on another host as an atomic success across all hosts.
|
|
56
|
+
|
|
57
|
+
A store timeout or malformed acknowledgement may occur after the OS has written the new value. On failure, Aptly attempts to restore the previous value (or remove the new entry if none existed), then reads it back. `credential_rollback_failed` is added to the original failure codes when recovery cannot be confirmed; do not assume either key is active. Check the OS credential store before retrying. This is best-effort recovery, not an atomic transaction across processes or hosts.
|
|
58
|
+
|
|
59
|
+
Restart MCP, then inspect `provider`, candidates, and `credential_status` with `get_routing_capabilities`. `os_store` means a key was loaded, not that the API authenticated it. Default and public-variable setup continue to preserve custom wrappers. API-key setup does not change host settings for an unverified launch path and restores that host's previous key where possible if storage was already attempted. Do not assume a new key automatically takes effect through an existing wrapper. These commands do not bypass Codex `/hooks` trust or host permissions.
|
|
60
|
+
|
|
61
|
+
### Recover an incompatible launcher
|
|
62
|
+
|
|
63
|
+
These options require Aptly 0.1.2 or later and are not in npm 0.1.1. To test from source, run `npm ci --ignore-scripts` and `npm run build`, then replace `aptly` below with `node bin/aptly.ts`.
|
|
64
|
+
|
|
65
|
+
Key setup diagnoses selected hosts before input or storage. If any host fails, it does not prompt or change any host. `--check` does not access keys or the credential store. `credential_node_mismatch`, `credential_server_mismatch`, and `credential_runtime_unsupported` identify incompatible Node paths, server paths, and OS-store support respectively.
|
|
66
|
+
|
|
67
|
+
If only Claude failed, diagnose that host and review migration only when `launcher_migration_available` is returned:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
aptly set env OPENAI_API_KEY --client claude --check
|
|
71
|
+
aptly setup --client claude --migrate-launcher --dry-run
|
|
72
|
+
aptly setup --client claude --migrate-launcher
|
|
73
|
+
aptly set env OPENAI_API_KEY --client claude
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`--dry-run` makes no changes. Migration replaces the Node/server paths of a receipt-matching, Aptly-owned standard registration with the current build. It preserves environment settings, Hooks, policy and other hosts, accesses no credentials, and never executes the old launcher. Custom wrappers and missing or modified ownership records are rejected. Review such registrations locally; use the wrapper's secure environment or a separately reviewed standard registration. Do not edit or delete ownership records to bypass validation.
|
|
77
|
+
|
|
78
|
+
A successful Codex configuration needs no reset. Retry only the affected host and restart MCP. Codex still requires `/hooks` trust review. Changes after diagnosis stop with `concurrent_configuration_change`. If recovery observes another key or cannot read the current key, it leaves the store unchanged and reports `credential_rollback_failed`. Files and the OS store do not form an atomic transaction; avoid concurrent configuration operations.
|
|
79
|
+
|
|
25
80
|
### Keys and restarting
|
|
26
81
|
|
|
27
|
-
|
|
82
|
+
Pass the classification key, `OPENAI_API_KEY`, through a secure environment or credential launcher to the MCP process. It is separate from host subscription login. Never write key values into command arguments, requests, configuration files, source, logs, or temporary files.
|
|
28
83
|
|
|
29
|
-
|
|
84
|
+
### MCP environment setup, step by step
|
|
30
85
|
|
|
31
|
-
|
|
86
|
+
Run `setup`, then merge the examples below into the existing `aptly` registration. Preserve `command`, `args`, credential launchers, `ROUTER_LEDGER_PATH`, and `APTLY_HOOK_POLICY_PATH`. Setup creates the private ledger/policy directories; a manual ledger path must be absolute and inside a user-owned directory with mode 700.
|
|
32
87
|
|
|
33
|
-
|
|
88
|
+
#### Configuration file locations
|
|
89
|
+
|
|
90
|
+
| Host | User registration used by Aptly |
|
|
34
91
|
|---|---|
|
|
35
|
-
|
|
|
36
|
-
| `
|
|
37
|
-
|
|
92
|
+
| Codex | `$CODEX_HOME/config.toml`; `~/.codex/config.toml` when `CODEX_HOME` is unset |
|
|
93
|
+
| Claude Code | `mcpServers.aptly` in `~/.claude.json`; `.claude.json` inside `CLAUDE_CONFIG_DIR` when that directory is configured |
|
|
94
|
+
|
|
95
|
+
Claude Code stores Hooks in `~/.claude/settings.json` by default, or `$CLAUDE_CONFIG_DIR/settings.json` when `CLAUDE_CONFIG_DIR` is set. This is separate from MCP registration. If project `.mcp.json`, managed settings, or account-specific directories are in use, check the active entry in `/mcp` before editing or adding a registration.
|
|
96
|
+
|
|
97
|
+
#### Passing the API key
|
|
98
|
+
|
|
99
|
+
For a direct launch, enter the key in **Bash** without displaying or saving its value, then start the host from that shell. In zsh, run `bash` first:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
read -rsp 'OpenAI API key: ' OPENAI_API_KEY
|
|
103
|
+
printf '\n'
|
|
104
|
+
export OPENAI_API_KEY
|
|
105
|
+
codex
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Replace `codex` with `claude` for Claude Code. This does not save the key permanently. A running GUI does not inherit another terminal’s environment; use its secure environment mechanism or preserve the existing credential launcher.
|
|
109
|
+
|
|
110
|
+
#### Codex example
|
|
111
|
+
|
|
112
|
+
Edit the existing `[mcp_servers.aptly]` tables; do not append duplicate tables. Add `OPENAI_API_KEY` to `env_vars` without removing existing entries. `env_vars` forwards named host variables; `.env` supplies fixed MCP values.
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[mcp_servers.aptly]
|
|
116
|
+
env_vars = ["OPENAI_API_KEY"]
|
|
117
|
+
|
|
118
|
+
[mcp_servers.aptly.env]
|
|
119
|
+
ROUTER_PROVIDER = "decisions"
|
|
120
|
+
APTLY_CLAUDE_MODELS = '["haiku","sonnet","opus"]'
|
|
121
|
+
APTLY_CODEX_MODELS = '["gpt-6-luna","gpt-6.1-terra","gpt-6.1-sol"]'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Claude Code example
|
|
125
|
+
|
|
126
|
+
Merge these values into the existing `mcpServers.aptly.env` object:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"ROUTER_PROVIDER": "decisions",
|
|
131
|
+
"APTLY_CLAUDE_MODELS": "[\"haiku\",\"sonnet\",\"opus\"]",
|
|
132
|
+
"APTLY_CODEX_MODELS": "[\"gpt-6-luna\",\"gpt-6.1-terra\",\"gpt-6.1-sol\"]"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
For direct launches, this optional reference forwards a key already present in the Claude Code environment. Do not add it to a credential-launcher setup. If the variable is missing, the key will not be supplied and the reference may remain unexpanded:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"OPENAI_API_KEY": "${OPENAI_API_KEY}"
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Model candidates are **JSON strings**: leave them unset for defaults or use `[]` to disable that host’s recommendations. Aptly reads the MCP startup environment and does not load project `.env` files.
|
|
145
|
+
|
|
146
|
+
Restart the host or MCP server after changes. **In Codex, review and trust the new Hook through `/hooks`.** Check `/mcp` and `get_routing_capabilities` for `provider`, candidates, and `automatic_hook.mode`. This free query does not authenticate the key; `recommend_agent` may incur a charge. For `unauthorized`, check key forwarding; for `needs_context`, check the task summary.
|
|
147
|
+
|
|
148
|
+
See the official [Codex configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference) and [Claude Code MCP guide](https://code.claude.com/docs/en/mcp) for configuration locations and environment forwarding.
|
|
38
149
|
|
|
39
150
|
### Skipping registration and removing it
|
|
40
151
|
|
|
41
152
|
```sh
|
|
42
|
-
APTLY_SKIP_SETUP=1 npm install
|
|
153
|
+
APTLY_SKIP_SETUP=1 npm install -g aptly@latest
|
|
43
154
|
aptly setup --client codex --mode defaults
|
|
44
155
|
aptly remove --client all
|
|
45
156
|
```
|
|
46
157
|
|
|
47
|
-
|
|
158
|
+
`CI` or npm `--ignore-scripts` also skips registration. Use `setup` to register later. To change mode, remove the registration and run setup with the desired `--mode`; `advisory` only supplies advice. For `partial`, check each host’s error codes. Removal preserves user-modified entries and reports conflicts.
|
|
48
159
|
|
|
49
160
|
## Automatic Hook
|
|
50
161
|
|
|
@@ -66,6 +177,20 @@ The CLI without additional configuration, and existing manual configurations, de
|
|
|
66
177
|
| `get_routing_precedence` | Explains preserved choices and unverified configuration sources for a call |
|
|
67
178
|
| `route_spawn_hook` | Selects defaults for eligible calls or passes advice only, according to the installed policy |
|
|
68
179
|
|
|
180
|
+
### Outbound data and disabling automatic sharing
|
|
181
|
+
|
|
182
|
+
For automatic classification, `summary` is an **excerpt assembled from an accepted task label and the clipped first paragraph** of the body. It is not a semantic rewrite or anonymization. Its UTF-8 size is at most `min(4000, max_summary_bytes)`; this is not a limit on the whole HTTP request. The opaque-message fallback in Codex uses only a sufficiently descriptive `task_name`, without decoding or transmitting that body. Labels can also contain sensitive information.
|
|
183
|
+
|
|
184
|
+
Decisions receives `client`, `task.summary`, `task.operation`, `task.context_sufficient`, candidate profile IDs, model/effort descriptions, and configured model facts. The classification API key is sent in `Authorization`; the request ID is sent in `X-Client-Request-Id`. Automatic IDs are hashes; direct recommendation IDs are caller-supplied. Do not put secrets in IDs or candidate descriptions.
|
|
185
|
+
|
|
186
|
+
To disable automatic sharing, change **only `enabled` to `false`** in the existing private policy file referenced by `APTLY_HOOK_POLICY_PATH`. Preserve the other fields and ownership record. Subsequent automatic Hook calls preserve the original call before classification or creation of a call-binding file. This cannot undo a transmission already started or recall information received by the server. Editing a generated policy can cause ownership conflicts in setup, configuration, or removal commands; those commands do not overwrite the disabled policy. Do not edit ownership records to bypass the checks.
|
|
187
|
+
|
|
188
|
+
`mode: advisory` still transmits classification data; it is not a privacy opt-out. Removing `APTLY_HOOK_POLICY_PATH` can activate the older strict path, so do not use removal as an alternative. `enabled: false` does not block explicit `recommend_agent` or `aptly recommend` requests.
|
|
189
|
+
|
|
190
|
+
For control over the shared summary, disable automatic sharing and write only the information needed for a direct recommendation. Aptly does not automatically fetch documents at URLs or attach source files mentioned in the summary. Checks for known key and Bearer patterns do not provide complete secret detection or establish that text is safe to transmit.
|
|
191
|
+
|
|
192
|
+
The ledger and Hook bindings store request metadata, hashes, and cached results, not task excerpts. Aptly diagnostics also exclude raw task text. The local Hook's `updatedInput` retains the original task so the host can continue execution. Aptly does not control the host's own transcript or log retention.
|
|
193
|
+
|
|
69
194
|
## Direct recommendations
|
|
70
195
|
|
|
71
196
|
The `recommend_agent` MCP tool and CLI `recommend` accept a task summary and recommend a profile. They do not spawn subagents. Pass this JSON as MCP tool arguments, or save it to a file and provide it to the CLI through standard input.
|
|
@@ -164,6 +289,14 @@ These are USD conversions of measured native tokens at the [official Standard AP
|
|
|
164
289
|
|
|
165
290
|
The measured workflow was **explicit MCP recommendation → native execution with the recommended profile passed as arguments**. It did not test automatic Hook URL retrieval or forwarding. The prior benchmark was reused as the control, with three samples per condition. Full-document reads, matching source quotes, and output structure were checked, but the results do not establish equal quality, statistical significance, or savings for other tasks.
|
|
166
291
|
|
|
292
|
+
### Interrupted processes and ledger locks
|
|
293
|
+
|
|
294
|
+
This locking design requires Aptly `0.1.2` or later and is not included in npm `0.1.1`. The JSON ledger keeps its request IDs, `unknown` records, completed cache, call counts, and reserved costs. Only persistent ledgers use Node.js 24's built-in SQLite. The adjacent `ledger.json.lock` remains after a normal exit; its presence alone does not mean an active lock. With the new design, process exit releases the OS lock so a later request can use the same ledger. It does not retry an existing uncertain ID or refund reserved costs.
|
|
295
|
+
|
|
296
|
+
Keep the ledger and lock in a private directory on a local filesystem that supports hard links, and use one canonical path for each ledger. Network shares, cloud-synced directories, and path aliases are outside the supported scope. Do not delete or replace the new lock or SQLite journal, or open them with another database tool while in use. Age and PID alone do not establish that an owner has exited.
|
|
297
|
+
|
|
298
|
+
An old empty `.lock` cannot establish whether its owner is still alive, so it is never initialized or removed automatically. Stop every relevant host, MCP process, and ledger-accessing process, including older versions, and upgrade all writers. Only after confirming that the file belongs to the legacy locking design may you quarantine that file and restart against the same JSON ledger path. Do not reset or delete the ledger, `unknown` records, costs, or completed results. If ownership or format is uncertain, leave access blocked and investigate.
|
|
299
|
+
|
|
167
300
|
## Diagnostics and development
|
|
168
301
|
|
|
169
302
|
```sh
|
package/docs/guide/ja.md
CHANGED
|
@@ -4,47 +4,158 @@
|
|
|
4
4
|
|
|
5
5
|
[README に戻る](../../README.ja.md)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
韓国語版が正本です。このガイドでは Aptly の基本的なインストール方法と使い方を説明します。パッケージをインストールできることは、すべてのアカウントでモデルにアクセスできることを意味しません。子エージェントの実行・承認・サンドボックス・MCP 権限は、Claude Code または Codex が管理します。
|
|
8
8
|
|
|
9
9
|
## インストール
|
|
10
10
|
|
|
11
|
-
Node.js 24 以上と Claude Code または Codex
|
|
11
|
+
Node.js 24 以上と Claude Code または Codex が必要です。npm の最新安定版をグローバルにインストールするには、次のコマンドを実行してください:
|
|
12
|
+
|
|
13
|
+
**既存の永続台帳を 0.1.2 以降に更新する前に**、その台帳にアクセスする可能性があるすべてのホスト、MCP サーバー、単独 CLI、旧版プロセスを停止してください。新しい永続ロックは旧版の書き込み側と併用できません。新規インストールでは旧ロックの隔離は不要です。旧版の空のロックが残る場合は、[台帳の移行手順](#プロセス中断と台帳ロック)に従い、確認済みの旧ロックだけをオフラインで隔離し、JSON 台帳、`unknown` 記録、費用、完了済みキャッシュを保持してください。
|
|
12
14
|
|
|
13
15
|
```sh
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
npm install -g aptly@latest
|
|
17
|
+
aptly setup --client all --mode defaults
|
|
18
|
+
aptly --version
|
|
17
19
|
```
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
`aptly --version` でインストール済みのバージョンを確認してください。Node.js 環境を切り替えると再インストールが必要な場合があります。
|
|
20
22
|
|
|
21
23
|
`postinstall` は、現在のユーザーの既存のホスト設定ディレクトリに MCP と `PreToolUse` Hook を登録します。`CODEX_HOME`・`CLAUDE_CONFIG_DIR` を使う場合は、インストールプロセスにも同じ環境を渡してください。まだ存在しないホストディレクトリは自動登録ではスキップし、明示的な `setup` で作成できます。必要なホストだけを登録するには、`--client codex` または `--client claude` を使用してください。
|
|
22
24
|
|
|
23
25
|
新規登録では `ROUTER_PROVIDER=decisions`、Hook の `defaults` ポリシー、ホストごとの非公開台帳を指定します。他の既存設定・Hook と、既存の Aptly のコマンド・環境・provider・台帳パスは保持します。既存の fixture 設定を自動で有料モードに切り替えることはありません。
|
|
24
26
|
|
|
27
|
+
### CLI による設定
|
|
28
|
+
|
|
29
|
+
`set` コマンドは 0.1.1 以降で利用できます。既存の起動パスは自動で切り替えません。API キー設定は、現在のパッケージの標準 Node/サーバー登録で、OS 資格情報の参照に対応する実行環境だと確認できた場合にのみ使用できます。独自ラッパー、旧バージョン、別のインストール先は `credential_launcher_unverified` で拒否します。登録を明示的に切り替えるかアップグレードしてから、再度実行してください。
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
aptly set default
|
|
33
|
+
aptly set env APTLY_CODEX_MODELS
|
|
34
|
+
aptly set env OPENAI_API_KEY
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
最初のコマンドは Claude Code と Codex を登録し、未設定のデフォルト環境設定を追加します。既存の起動コマンド、環境変数の許可リスト、分類方式、独自の候補、advisory ポリシーは保持します。次のコマンドは入力を表示せずに値を尋ね、指定した変数だけを変更します。最後のコマンドは API キーを OS の資格情報ストアに保存し、選択したホストの起動時に読み込むよう設定します。値をコマンド引数に渡さないでください。
|
|
38
|
+
|
|
39
|
+
既定では両ホストを選択します。`--client codex`、`--client claude`、`--client all` で対象を指定できます。Claude 候補には `["haiku","sonnet","opus"]` のような JSON 文字列を入力してください。
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
aptly set env APTLY_CLAUDE_MODELS --client claude
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
自動化では `--stdin` を明示してください。以下は公開変数の例です。実際のキーを `printf` コマンドやシェル履歴に含めないでください。
|
|
46
|
+
|
|
47
|
+
```sh
|
|
48
|
+
printf '%s\n' '["gpt-6.1-terra"]' | aptly set env APTLY_CODEX_MODELS --stdin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
設定できる公開キーは `ROUTER_PROVIDER`(`fixture` または `decisions`)、`APTLY_CLAUDE_MODELS`、`APTLY_CODEX_MODELS`、`CLAUDE_MODELS`、`CODEX_MODELS`、`APTLY_MODEL_INFO_PATH` です。候補は対応モデルの JSON 配列文字列で、無効な値、重複、正式名と別名の競合は拒否します。`[]` は該当ホストの推薦を無効にします。モデルキャッシュには非公開ディレクトリ内の絶対パスが必要です。台帳や Hook ポリシーの管理パスはこのコマンドで変更できません。
|
|
52
|
+
|
|
53
|
+
API キーは macOS Keychain、インストール済みの Linux `secret-tool`、または Windows Credential Manager に保存します。Windows バックエンドは PowerShell と、現在のユーザー範囲の Win32 Generic 資格情報を使用し、UTF-8 データの上限は 2,560 バイトです。Windows CI では、合成キーの保存・読み取り・更新・削除、Unicode パス、分離したホスト設定、キー参照、ACL の保持を確認しました。Windows 上の実際の Claude Code・Codex セッションを実行して検証したものではありません。ストアを利用できない場合はエラーとなり、平文ファイルには切り替えません。キーはホスト別アカウントに分け、MCP ファイルには `APTLY_SECRET_BACKEND=os` と `APTLY_SECRET_CLIENT` の参照だけを保存します。OS ストアを選択した後、キーがない場合や読み取りに失敗した場合も、別の環境変数キーに黙って切り替えません。`set default` は既存のラッパーや環境による認証を保持し、`set env OPENAI_API_KEY` が OS ストア認証を明示的に選択します。
|
|
54
|
+
|
|
55
|
+
結果にはホストごとの状態と固定エラーコードだけを返し、キーの値は表示しません。`partial` の場合は各ホストを確認してください。`credential_store_failed` ではストアへのアクセスや対応状況を、`credential_rollback_failed` では以前のキーを復元できたかを確認します。失敗したホストの旧キーは可能な場合に復元します。他のホストの成功を、全ホストでの原子的な成功とみなさないでください。
|
|
56
|
+
|
|
57
|
+
保存のタイムアウトや応答解析の失敗は、OS が新しい値を書き込んだ後にも起こり得ます。失敗時は以前の値を復元し、以前の値がなければ新しい項目を削除して、再読み込みで確認します。復旧を確認できない場合は、元のエラーコードに `credential_rollback_failed` を追加します。どちらのキーが有効かを断定せず、再試行前に OS の資格情報ストアを確認してください。これは可能な範囲での復旧であり、プロセスやホストをまたぐ原子的なトランザクションではありません。
|
|
58
|
+
|
|
59
|
+
変更後は MCP を再起動し、`get_routing_capabilities` の `provider`、候補、`credential_status` を確認してください。`os_store` はキーを読み込めたことを示し、API 認証の成功を示すものではありません。デフォルト設定と公開変数の設定では、引き続き独自ラッパーを保持します。API キー設定は未確認の起動パスのホスト設定を変更せず、保存を試みていた場合は可能な限りそのホストの旧キーを復元します。既存のラッパーにも新しいキーが自動で適用されるとは想定しないでください。Codex の `/hooks` 信頼承認やホスト権限は迂回しません。
|
|
60
|
+
|
|
61
|
+
### 起動パスのエラーからの復旧
|
|
62
|
+
|
|
63
|
+
以下のオプションは Aptly 0.1.2 以降で利用でき、npm 0.1.1 には含まれません。ソースから試す場合は `npm ci --ignore-scripts` と `npm run build` を実行し、以下の `aptly` を `node bin/aptly.ts` に置き換えます。
|
|
64
|
+
|
|
65
|
+
キー設定は入力・保存前に対象ホストを診断します。いずれかが失敗すると入力を求めず、全ホストを変更しません。`--check` はキーや資格情報ストアにアクセスしません。`credential_node_mismatch`、`credential_server_mismatch`、`credential_runtime_unsupported` はそれぞれ Node パス、サーバーパス、OS ストア対応の不一致を示します。
|
|
66
|
+
|
|
67
|
+
Claude だけが失敗した場合は次の順序で診断し、`launcher_migration_available` の場合にのみ移行を検討してください。
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
aptly set env OPENAI_API_KEY --client claude --check
|
|
71
|
+
aptly setup --client claude --migrate-launcher --dry-run
|
|
72
|
+
aptly setup --client claude --migrate-launcher
|
|
73
|
+
aptly set env OPENAI_API_KEY --client claude
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`--dry-run` は変更しません。移行は所有記録と一致する Aptly の標準登録に限り、Node・サーバーパスを現在のビルドへ更新します。環境設定・Hook・ポリシー・他のホストを保持し、資格情報へのアクセスや古い起動プログラムの実行は行いません。独自ラッパー、所有記録のない登録、変更済みの登録は拒否します。その場合は登録をローカルで確認し、ラッパーの安全な環境変数受け渡しを使うか、別途確認した標準登録へ切り替えてください。検証を回避するために所有記録を編集・削除しないでください。
|
|
77
|
+
|
|
78
|
+
成功した Codex の再設定は不要です。失敗したホストだけを指定して再試行し、MCP を再起動してください。Codex では引き続き `/hooks` の信頼確認が必要です。診断後の設定変更は `concurrent_configuration_change` で中断します。復旧時に別のキーを検出した場合や現在値を読めない場合は上書きせず、`credential_rollback_failed` を返します。ファイルと OS ストアは原子的なトランザクションではないため、設定操作を同時に実行しないでください。
|
|
79
|
+
|
|
25
80
|
### キーと再起動
|
|
26
81
|
|
|
27
|
-
`OPENAI_API_KEY`
|
|
82
|
+
分類用の `OPENAI_API_KEY` は、安全な環境や資格情報ランチャーを通して MCP プロセスに渡してください。ホストのサブスクリプション認証とは別です。キーの値をコマンド引数・リクエスト・設定ファイル・ソース・ログ・一時ファイルに記録しないでください。
|
|
28
83
|
|
|
29
|
-
|
|
84
|
+
### MCP 環境変数の設定手順
|
|
30
85
|
|
|
31
|
-
|
|
86
|
+
`setup` 後、以下の例を既存の `aptly` 登録に統合してください。`command`、`args`、資格情報ランチャー、`ROUTER_LEDGER_PATH`、`APTLY_HOOK_POLICY_PATH` は保持します。Setup は非公開の台帳・ポリシーディレクトリを作成します。台帳を手動指定する場合は、ユーザー所有で権限 700 のディレクトリ内の絶対パスを使ってください。
|
|
32
87
|
|
|
33
|
-
|
|
88
|
+
#### 設定ファイルの場所
|
|
89
|
+
|
|
90
|
+
| ホスト | Aptly が使用するユーザー登録の場所 |
|
|
34
91
|
|---|---|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
92
|
+
| Codex | `$CODEX_HOME/config.toml`。`CODEX_HOME` 未指定の場合は `~/.codex/config.toml` |
|
|
93
|
+
| Claude Code | `~/.claude.json` の `mcpServers.aptly`。`CLAUDE_CONFIG_DIR` 指定時は、そのディレクトリの `.claude.json` |
|
|
94
|
+
|
|
95
|
+
Claude Code の Hook ファイルは通常 `~/.claude/settings.json` ですが、`CLAUDE_CONFIG_DIR` を指定すると `$CLAUDE_CONFIG_DIR/settings.json` になります。MCP 登録とは別です。プロジェクトの `.mcp.json`、管理設定、アカウント別ディレクトリを使う場合は、編集・追加前に `/mcp` で有効な登録を確認してください。
|
|
96
|
+
|
|
97
|
+
#### API キーの渡し方
|
|
98
|
+
|
|
99
|
+
直接起動する場合は、**Bash** でキーを画面やコマンド履歴に残さず入力し、同じシェルからホストを起動します。zsh では先に `bash` を実行してください:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
read -rsp 'OpenAI API key: ' OPENAI_API_KEY
|
|
103
|
+
printf '\n'
|
|
104
|
+
export OPENAI_API_KEY
|
|
105
|
+
codex
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Claude Code では `codex` を `claude` に置き換えます。キーは永続保存されません。起動済み GUI は別のターミナルの環境を継承しないため、アプリの安全な環境受け渡し機能か既存の資格情報ランチャーを使ってください。
|
|
109
|
+
|
|
110
|
+
#### Codex の例
|
|
111
|
+
|
|
112
|
+
既存の `[mcp_servers.aptly]` テーブルを編集し、同じテーブルを重複追加しないでください。`env_vars` の既存項目を保持して `OPENAI_API_KEY` を追加します。`env_vars` はホストの環境変数を名前で転送し、`.env` は MCP に固定値を渡します。
|
|
113
|
+
|
|
114
|
+
```toml
|
|
115
|
+
[mcp_servers.aptly]
|
|
116
|
+
env_vars = ["OPENAI_API_KEY"]
|
|
117
|
+
|
|
118
|
+
[mcp_servers.aptly.env]
|
|
119
|
+
ROUTER_PROVIDER = "decisions"
|
|
120
|
+
APTLY_CLAUDE_MODELS = '["haiku","sonnet","opus"]'
|
|
121
|
+
APTLY_CODEX_MODELS = '["gpt-6-luna","gpt-6.1-terra","gpt-6.1-sol"]'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Claude Code の例
|
|
125
|
+
|
|
126
|
+
既存の `mcpServers.aptly.env` オブジェクトに以下を統合してください:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"ROUTER_PROVIDER": "decisions",
|
|
131
|
+
"APTLY_CLAUDE_MODELS": "[\"haiku\",\"sonnet\",\"opus\"]",
|
|
132
|
+
"APTLY_CODEX_MODELS": "[\"gpt-6-luna\",\"gpt-6.1-terra\",\"gpt-6.1-sol\"]"
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
直接起動では、次の任意の参照で Claude Code の環境にあるキーを渡せます。資格情報ランチャーを使う設定には追加しないでください。変数がない場合はキーが渡らず、参照文字列が未展開のまま残ることがあります:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"OPENAI_API_KEY": "${OPENAI_API_KEY}"
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
モデル候補は **JSON 文字列**です。未設定ならデフォルトを使い、`[]` はそのホストの推薦を無効にします。Aptly は MCP 起動時の環境を読み、プロジェクトの `.env` ファイルは自動で読み込みません。
|
|
145
|
+
|
|
146
|
+
変更後はホストまたは MCP を再起動してください。**Codex では `/hooks` で新しい Hook を確認して信頼を承認します。** `/mcp` と `get_routing_capabilities` で `provider`、候補、`automatic_hook.mode` を確認してください。この無料照会はキーの認証を検証せず、`recommend_agent` には料金が発生する場合があります。`unauthorized` ではキーの受け渡し、`needs_context` ではタスク要約を確認してください。
|
|
147
|
+
|
|
148
|
+
設定場所と受け渡し方式の公式説明は、[Codex 構成リファレンス](https://learn.chatgpt.com/docs/config-file/config-reference)と [Claude Code MCP ガイド](https://code.claude.com/docs/en/mcp)を参照してください。
|
|
38
149
|
|
|
39
150
|
### スキップ・削除
|
|
40
151
|
|
|
41
152
|
```sh
|
|
42
|
-
APTLY_SKIP_SETUP=1 npm install
|
|
153
|
+
APTLY_SKIP_SETUP=1 npm install -g aptly@latest
|
|
43
154
|
aptly setup --client codex --mode defaults
|
|
44
155
|
aptly remove --client all
|
|
45
156
|
```
|
|
46
157
|
|
|
47
|
-
`CI`
|
|
158
|
+
`CI` や npm `--ignore-scripts` でも登録をスキップします。後から `setup` で登録できます。モード変更時は登録を削除して希望の `--mode` で再設定します。`advisory` は推薦のみを返します。`partial` ではホスト別のエラーコードを確認してください。削除時はユーザー変更済みの項目を保持し、競合を報告します。
|
|
48
159
|
|
|
49
160
|
## 自動 Hook
|
|
50
161
|
|
|
@@ -66,6 +177,20 @@ aptly remove --client all
|
|
|
66
177
|
| `get_routing_precedence` | 呼び出しを保持する根拠と、未確認の設定元を説明します |
|
|
67
178
|
| `route_spawn_hook` | インストールしたポリシーに応じて、対象呼び出しのデフォルト値を選択するか、推薦だけを伝えます |
|
|
68
179
|
|
|
180
|
+
### 外部送信と自動共有の無効化
|
|
181
|
+
|
|
182
|
+
自動分類の `summary` は、有効なタスクラベルと本文の**最初の段落を切り詰めて組み合わせた抜粋**です。意味を再要約したものでも、匿名化したものでもありません。UTF-8 のサイズは `min(4000, max_summary_bytes)` 以下ですが、HTTP リクエスト全体の上限ではありません。Codex の opaque メッセージへのフォールバックでは、本文を復号・送信せず、十分に具体的な `task_name` だけを使用します。ラベルにも機密情報が含まれる可能性があります。
|
|
183
|
+
|
|
184
|
+
Decisions には `client`、`task.summary`、`task.operation`、`task.context_sufficient` と、候補プロファイル ID・モデルと effort の説明・設定したモデル特性を送信します。分類用 API キーは `Authorization` ヘッダー、リクエスト ID は `X-Client-Request-Id` ヘッダーで送信します。自動経路の ID はハッシュで、直接推薦の ID は呼び出し元が指定します。ID や候補の説明にも秘密情報を含めないでください。
|
|
185
|
+
|
|
186
|
+
自動共有を無効にするには、`APTLY_HOOK_POLICY_PATH` が指す既存の非公開ポリシーファイルで、**`enabled` だけを `false` に変更**してください。他のフィールドと所有権の記録は保持してください。その後の自動 Hook 呼び出しは、分類や呼び出しバインディングファイルの作成前に元の呼び出しを保持します。開始済みの送信を取り消したり、サーバーが受信した情報を回収したりすることはできません。生成済みのポリシーを変更すると、登録・設定・削除コマンドの所有権検査で競合する場合があり、それらのコマンドは無効化したポリシーを上書きしません。検査を回避するために所有権の記録を編集しないでください。
|
|
187
|
+
|
|
188
|
+
`mode: advisory` でも分類データは送信されるため、プライバシー上の共有停止にはなりません。`APTLY_HOOK_POLICY_PATH` を削除すると従来の strict 経路が有効になる場合があるため、共有停止の代わりにしないでください。`enabled: false` は、明示的な `recommend_agent` や `aptly recommend` のリクエストを止めるものではありません。
|
|
189
|
+
|
|
190
|
+
共有する要約を自分で選ぶ場合は、自動共有を無効にしてから直接推薦に必要な情報だけを記述してください。Aptly は要約中の URL の文書や、言及されたソースファイルを自動取得・添付しません。既知のキーや Bearer のパターン検査は、完全な秘密情報の検出や送信の安全性を保証しません。
|
|
191
|
+
|
|
192
|
+
台帳と Hook バインディングにはリクエストのメタデータ・ハッシュ・キャッシュ結果を保存し、タスクの抜粋は保存しません。Aptly の診断にもタスク原文を含めません。ただし、ローカルの Hook の `updatedInput` は、ホストが実行を続けられるよう元のタスクを保持します。ホスト自身の会話やログの保存は Aptly の制御対象ではありません。
|
|
193
|
+
|
|
69
194
|
## 直接推薦
|
|
70
195
|
|
|
71
196
|
`recommend_agent` MCP と CLI の `recommend` は、タスク要約を受け取ってプロファイルを推薦します。子エージェントを直接生成することはありません。以下の JSON を MCP ツールの引数として渡すか、ファイルに保存して CLI の標準入力に渡してください。
|
|
@@ -164,6 +289,14 @@ Codex が子エージェントの `message` を暗号文として Hook に渡す
|
|
|
164
289
|
|
|
165
290
|
測定経路は、**明示的な MCP 推薦 → 推薦プロファイルを引数として渡したホスト上での実行**です。自動 Hook の URL 収集・伝達機能を検証したものではありません。基準群は直前の実測を再利用しており、条件ごとの標本は 3 回です。ドキュメント全体の読み取り・原文の引用一致・出力形式は確認しましたが、品質の同等性、統計的有意性、他のタスクでの費用削減を保証するものではありません。
|
|
166
291
|
|
|
292
|
+
### プロセス中断と台帳ロック
|
|
293
|
+
|
|
294
|
+
このロック方式は Aptly `0.1.2` 以降で利用でき、npm `0.1.1` には含まれません。JSON 台帳のリクエスト ID・`unknown`・完了済みキャッシュ・呼び出し数・予約費用の形式は維持します。永続台帳だけが Node.js 24 内蔵の SQLite を使用します。隣接する `ledger.json.lock` は正常終了後も残るため、ファイルの存在だけではロックが使用中かどうかを判断できません。新方式ではプロセス終了時に OS のロックが解放され、後続のリクエストが同じ台帳を使用できます。結果が不明な既存 ID の再試行や予約費用の返却は行いません。
|
|
295
|
+
|
|
296
|
+
台帳とロックは、ハードリンクに対応したローカルファイルシステムの非公開ディレクトリに置き、各台帳に同一の正規パスを使用してください。ネットワーク共有・クラウド同期ディレクトリ・パスの別名はサポート範囲外です。新しいロックや SQLite journal を削除・置換したり、使用中に他の DB ツールで開いたりしないでください。ファイルの古さや PID だけでは所有プロセスの終了を確認できません。
|
|
297
|
+
|
|
298
|
+
旧版の空の `.lock` ファイルでは所有プロセスが生存しているかを確認できないため、自動で初期化・削除しません。旧版を含む関連ホスト・MCP・台帳にアクセスするすべてのプロセスを停止し、書き込み側をすべて新しい版に更新してください。旧方式のロックであると確認できた場合だけ、そのファイルを別途隔離し、同じ JSON 台帳パスで再開します。台帳・`unknown`・費用・完了結果を初期化・削除しないでください。所有者や形式を確認できない場合は、遮断状態を保って調査してください。
|
|
299
|
+
|
|
167
300
|
## 診断と開発
|
|
168
301
|
|
|
169
302
|
```sh
|