praxis-agent 0.53.0 → 0.53.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/dist/native/context.js +26 -8
- package/dist/native/dynamic-context.js +32 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,7 +227,11 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
227
227
|
existing default behavior. This is a Praxis permission contract, not a claim
|
|
228
228
|
of verified Claude Code 2.1.208 parity. Explicit concrete `--tools`
|
|
229
229
|
selections load selected tools directly, while
|
|
230
|
-
`--disallowedTools ToolSearch` restores the complete tool list.
|
|
230
|
+
`--disallowedTools ToolSearch` restores the complete tool list. For each
|
|
231
|
+
context assembly, Git status is refreshed from the caller-resolved cwd while
|
|
232
|
+
environment and memory remain lifecycle-stable; collection uses
|
|
233
|
+
`--no-optional-locks`, fails closed on repository/status errors, and bounds
|
|
234
|
+
the rendered status to 2,048 UTF-8 bytes.
|
|
231
235
|
- **Provider-neutral models** — native Provider Registry/Vault routing, API
|
|
232
236
|
adapters, an experimental Codex OAuth adapter, explicit capability checks,
|
|
233
237
|
separate per-attempt connect, byte-idle, and absolute-total timeouts, typed
|
package/dist/native/context.js
CHANGED
|
@@ -131,7 +131,7 @@ ${sections.join('\n\n')}`,
|
|
|
131
131
|
tailSections.push({
|
|
132
132
|
id: 'relocated-runtime-context',
|
|
133
133
|
placement: 'first-user',
|
|
134
|
-
stability: '
|
|
134
|
+
stability: 'volatile',
|
|
135
135
|
content: renderClaudeDynamicUserContext({
|
|
136
136
|
environment: dynamic.environment,
|
|
137
137
|
...(dynamic.gitStatus ? { gitStatus: dynamic.gitStatus } : {}),
|
|
@@ -143,8 +143,19 @@ ${sections.join('\n\n')}`,
|
|
|
143
143
|
id: 'runtime-context',
|
|
144
144
|
placement: 'system',
|
|
145
145
|
stability: 'session',
|
|
146
|
-
content: renderClaudeDynamicSystemContext(
|
|
146
|
+
content: renderClaudeDynamicSystemContext({
|
|
147
|
+
environment: dynamic.environment,
|
|
148
|
+
...(dynamic.memory ? { memory: dynamic.memory } : {}),
|
|
149
|
+
}),
|
|
147
150
|
});
|
|
151
|
+
if (dynamic.gitStatus) {
|
|
152
|
+
tailSections.push({
|
|
153
|
+
id: 'git-status',
|
|
154
|
+
placement: 'system',
|
|
155
|
+
stability: 'volatile',
|
|
156
|
+
content: dynamic.gitStatus,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
148
159
|
}
|
|
149
160
|
}
|
|
150
161
|
const composition = this.composer.compose({
|
|
@@ -227,15 +238,22 @@ ${sections.join('\n\n')}`,
|
|
|
227
238
|
throw new Error('Dynamic context loader is unavailable');
|
|
228
239
|
if (!snapshot)
|
|
229
240
|
return load(cwd);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
241
|
+
const current = load(cwd);
|
|
242
|
+
if (!snapshot.stableDynamic) {
|
|
243
|
+
const pending = current.then(({ environment, memory }) => ({
|
|
244
|
+
environment,
|
|
245
|
+
...(memory ? { memory } : {}),
|
|
246
|
+
}));
|
|
247
|
+
snapshot.stableDynamic = pending;
|
|
233
248
|
void pending.catch(() => {
|
|
234
|
-
if (snapshot.
|
|
235
|
-
delete snapshot.
|
|
249
|
+
if (snapshot.stableDynamic === pending)
|
|
250
|
+
delete snapshot.stableDynamic;
|
|
236
251
|
});
|
|
237
252
|
}
|
|
238
|
-
return snapshot.
|
|
253
|
+
return Promise.all([current, snapshot.stableDynamic]).then(([fresh, stable]) => ({
|
|
254
|
+
...stable,
|
|
255
|
+
...(fresh.gitStatus ? { gitStatus: fresh.gitStatus } : {}),
|
|
256
|
+
}));
|
|
239
257
|
}
|
|
240
258
|
loadMcpInstructions(snapshot) {
|
|
241
259
|
const load = this.options.loadMcpInstructions;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { basename } from 'node:path';
|
|
3
3
|
import { platform, release, type } from 'node:os';
|
|
4
|
-
const MAX_GIT_OUTPUT_BYTES =
|
|
4
|
+
const MAX_GIT_OUTPUT_BYTES = 2_048;
|
|
5
|
+
const MAX_GIT_STATUS_BYTES = 2_048;
|
|
5
6
|
const MAX_GIT_ERROR_BYTES = 8 * 1024;
|
|
6
7
|
const GIT_TIMEOUT_MS = 5_000;
|
|
7
8
|
function collectBounded(chunks, chunk, state, limit) {
|
|
@@ -16,6 +17,22 @@ function collectBounded(chunks, chunk, state, limit) {
|
|
|
16
17
|
if (accepted.length < chunk.length)
|
|
17
18
|
state.truncated = true;
|
|
18
19
|
}
|
|
20
|
+
function boundUtf8(value, limit, marker) {
|
|
21
|
+
if (Buffer.byteLength(value, 'utf8') <= limit)
|
|
22
|
+
return value;
|
|
23
|
+
const markerBytes = Buffer.byteLength(marker, 'utf8');
|
|
24
|
+
const prefixLimit = Math.max(0, limit - markerBytes);
|
|
25
|
+
let bytes = 0;
|
|
26
|
+
let prefix = '';
|
|
27
|
+
for (const character of value) {
|
|
28
|
+
const characterBytes = Buffer.byteLength(character, 'utf8');
|
|
29
|
+
if (bytes + characterBytes > prefixLimit)
|
|
30
|
+
break;
|
|
31
|
+
prefix += character;
|
|
32
|
+
bytes += characterBytes;
|
|
33
|
+
}
|
|
34
|
+
return `${prefix}${marker}`;
|
|
35
|
+
}
|
|
19
36
|
function defaultRunGit(cwd, args) {
|
|
20
37
|
return new Promise((resolve, reject) => {
|
|
21
38
|
const child = spawn('git', ['-C', cwd, ...args], {
|
|
@@ -93,9 +110,16 @@ async function renderGitStatus(runGit) {
|
|
|
93
110
|
optionalGit(runGit, ['branch', '--show-current']),
|
|
94
111
|
optionalGit(runGit, ['branch', '--format=%(refname:short)']),
|
|
95
112
|
optionalGit(runGit, ['config', 'user.name']),
|
|
96
|
-
optionalGit(runGit, [
|
|
113
|
+
optionalGit(runGit, [
|
|
114
|
+
'--no-optional-locks',
|
|
115
|
+
'status',
|
|
116
|
+
'--short',
|
|
117
|
+
'--untracked-files=all',
|
|
118
|
+
]),
|
|
97
119
|
optionalGit(runGit, ['log', '-5', '--oneline']),
|
|
98
120
|
]);
|
|
121
|
+
if (!status.available)
|
|
122
|
+
return undefined;
|
|
99
123
|
const branch = branchValue.output || 'HEAD';
|
|
100
124
|
const sections = [
|
|
101
125
|
'# gitStatus',
|
|
@@ -108,18 +132,16 @@ async function renderGitStatus(runGit) {
|
|
|
108
132
|
if (user.available && user.output) {
|
|
109
133
|
sections.push('', `Git user: ${user.output}`);
|
|
110
134
|
}
|
|
111
|
-
const renderedStatus =
|
|
112
|
-
? '
|
|
113
|
-
: status.
|
|
114
|
-
?
|
|
115
|
-
:
|
|
116
|
-
? '... [truncated]'
|
|
117
|
-
: 'Clean';
|
|
135
|
+
const renderedStatus = status.output
|
|
136
|
+
? `${status.output}${status.truncated ? '\n... [truncated]' : ''}`
|
|
137
|
+
: status.truncated
|
|
138
|
+
? '... [truncated]'
|
|
139
|
+
: 'Clean';
|
|
118
140
|
sections.push('', 'Status:', renderedStatus);
|
|
119
141
|
if (commits.available && commits.output) {
|
|
120
142
|
sections.push('', 'Recent commits:', commits.output);
|
|
121
143
|
}
|
|
122
|
-
return sections.join('\n');
|
|
144
|
+
return boundUtf8(sections.join('\n'), MAX_GIT_STATUS_BYTES, '\n... [truncated]');
|
|
123
145
|
}
|
|
124
146
|
export async function loadClaudeDynamicContext(options) {
|
|
125
147
|
const configuredRunGit = options.runGit;
|