@event4u/agent-config 8.3.0 → 8.4.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/.claude-plugin/marketplace.json +4 -426
- package/.claude-plugin/skills/install-agent-config/SKILL.md +32 -0
- package/CHANGELOG.md +25 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +1 -1
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +1 -1
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +1 -1
- package/dist/mcp/registry-manifest.json +1 -1
- package/docs/contracts/surface-matrix.md +103 -0
- package/package.json +4 -1
- package/src/agent-src/README.md +64 -0
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +497 -0
- package/src/agent-src/scripts/scan-seeder-violations.php +145 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +1087 -0
- package/src/agent-src/templates/AGENTS.md +34 -0
- package/src/agent-src/templates/scripts/README.md +195 -0
- package/src/agent-src/templates/scripts/check_memory.ts +662 -0
- package/src/agent-src/templates/scripts/check_memory_proposal.ts +370 -0
- package/src/agent-src/templates/scripts/historical-bug-patterns.example.yml +84 -0
- package/src/agent-src/templates/scripts/implement_ticket/__main__.ts +27 -0
- package/src/agent-src/templates/scripts/memory_hash.ts +355 -0
- package/src/agent-src/templates/scripts/memory_lookup.ts +1089 -0
- package/src/agent-src/templates/scripts/memory_report.ts +868 -0
- package/src/agent-src/templates/scripts/memory_signal.ts +444 -0
- package/src/agent-src/templates/scripts/memory_status.ts +215 -0
- package/src/agent-src/templates/scripts/ownership-map.example.yml +87 -0
- package/src/agent-src/templates/scripts/pr-risk-config.example.yml +76 -0
- package/src/agent-src/templates/scripts/pr_review_routing.ts +544 -0
- package/src/agent-src/templates/scripts/pr_risk_review.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/aggregator.ts +0 -0
- package/src/agent-src/templates/scripts/telemetry/boundary.ts +164 -0
- package/src/agent-src/templates/scripts/telemetry/engagement.ts +479 -0
- package/src/agent-src/templates/scripts/telemetry/report_renderer.ts +394 -0
- package/src/agent-src/templates/scripts/telemetry/settings.ts +210 -0
- package/src/agent-src/templates/scripts/telemetry_record.ts +276 -0
- package/src/agent-src/templates/scripts/telemetry_report.ts +211 -0
- package/src/agent-src/templates/scripts/telemetry_status.ts +333 -0
- package/src/agent-src/templates/scripts/tier_usage_report.ts +619 -0
- package/src/agent-src/templates/scripts/work_engine/__main__.ts +14 -0
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +1261 -0
- package/src/agent-src/templates/scripts/work_engine/_lib/user_global_paths.ts +329 -0
- package/src/agent-src/templates/scripts/work_engine/cli.ts +206 -0
- package/src/agent-src/templates/scripts/work_engine/cli_args.ts +249 -0
- package/src/agent-src/templates/scripts/work_engine/delivery_state.ts +225 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/analyze.ts +125 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +189 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +94 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/memory.ts +193 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/plan.ts +267 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/refine.ts +518 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/report.ts +379 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +268 -0
- package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +258 -0
- package/src/agent-src/templates/scripts/work_engine/directives/index.ts +32 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/contract.ts +243 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/index.ts +108 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +259 -0
- package/src/agent-src/templates/scripts/work_engine/directives/mixed/ui.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/_passthrough.ts +40 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +241 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +216 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +506 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +325 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/index.ts +102 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +462 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +474 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +352 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/_skipped.ts +33 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/apply.ts +213 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/index.ts +111 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/refine.ts +126 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/report.ts +112 -0
- package/src/agent-src/templates/scripts/work_engine/directives/ui_trivial/test.ts +164 -0
- package/src/agent-src/templates/scripts/work_engine/dispatcher.ts +515 -0
- package/src/agent-src/templates/scripts/work_engine/emitters.ts +119 -0
- package/src/agent-src/templates/scripts/work_engine/errors.ts +24 -0
- package/src/agent-src/templates/scripts/work_engine/hook_bootstrap.ts +104 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/_chat_history_base.ts +189 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_append.ts +41 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/chat_history_halt_append.ts +89 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.ts +193 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/decision_trace.ts +304 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/directive_set_guard.ts +110 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/halt_surface_audit.ts +118 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/index.ts +17 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/memory_visibility.ts +161 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/state_shape_validation.ts +45 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/builtin/trace.ts +134 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/context.ts +94 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/events.ts +58 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/exceptions.ts +85 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/index.ts +27 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/registry.ts +66 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/runner.ts +90 -0
- package/src/agent-src/templates/scripts/work_engine/hooks/settings.ts +260 -0
- package/src/agent-src/templates/scripts/work_engine/input_builders.ts +260 -0
- package/src/agent-src/templates/scripts/work_engine/intent/classify.ts +466 -0
- package/src/agent-src/templates/scripts/work_engine/migration/v0_to_v1.ts +531 -0
- package/src/agent-src/templates/scripts/work_engine/orchestration.ts +366 -0
- package/src/agent-src/templates/scripts/work_engine/persona_policy.ts +97 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/diff.ts +135 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/file.ts +175 -0
- package/src/agent-src/templates/scripts/work_engine/resolvers/prompt.ts +115 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/confidence.ts +415 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_engine.ts +466 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/decision_trace.ts +298 -0
- package/src/agent-src/templates/scripts/work_engine/scoring/memory_visibility.ts +444 -0
- package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +252 -0
- package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +745 -0
- package/src/agent-src/templates/scripts/work_engine/state.ts +1151 -0
- package/src/agent-src/templates/scripts/work_engine/state_io.ts +413 -0
- package/src/config/surface-matrix.yml +213 -0
- package/src/install/atomic.ts +111 -0
- package/src/install/conflict.ts +226 -0
- package/src/install/detect.ts +280 -0
- package/src/install/paths.ts +90 -0
- package/src/install/plan.ts +205 -0
- package/src/install/preflight.ts +210 -0
- package/src/install/selectedTools.ts +52 -0
- package/src/install/toolDetection.ts +120 -0
- package/src/install/txlog.ts +161 -0
- package/src/install/types.ts +175 -0
- package/src/install/wizard-plan.ts +216 -0
- package/src/scripts/_cli/cmd_converge.ts +399 -0
- package/src/scripts/_cli/cmd_doctor.ts +94 -0
- package/src/scripts/_cli/cmd_upgrade.ts +40 -16
- package/src/scripts/_dispatch.bash +13 -0
- package/src/scripts/condense.ts +67 -36
- package/src/scripts/hook_manifest.yaml +16 -7
- package/src/scripts/lint_marketplace.ts +54 -56
- package/src/scripts/lint_surface_matrix.ts +200 -0
- package/src/scripts/prepack-check.mjs +108 -5
- package/src/scripts/surface_probe_hook.ts +231 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `./agent-config telemetry:status` — read-only status report.
|
|
4
|
+
*
|
|
5
|
+
* TypeScript twin of `telemetry_status.py` (ADR-200). Byte-for-byte parity on
|
|
6
|
+
* stdout / stderr / exit code for both text and JSON formats. Safe even when
|
|
7
|
+
* telemetry is disabled — never creates the log, never validates, never writes.
|
|
8
|
+
*/
|
|
9
|
+
import * as fs from 'node:fs';
|
|
10
|
+
import process from 'node:process';
|
|
11
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
|
|
14
|
+
import { EngagementSchemaError, parse_event } from './telemetry/engagement.js';
|
|
15
|
+
import { type TelemetrySettings, read_settings } from './telemetry/settings.js';
|
|
16
|
+
|
|
17
|
+
function _isFile(p: string): boolean {
|
|
18
|
+
try {
|
|
19
|
+
return fs.statSync(p).isFile();
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Return the `ts` of the last well-formed event, or null. Reads from the tail. */
|
|
26
|
+
function _last_event_ts(log_path: string): string | null {
|
|
27
|
+
if (!_isFile(log_path)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
let tail: string;
|
|
31
|
+
try {
|
|
32
|
+
const fd = fs.openSync(log_path, 'r');
|
|
33
|
+
try {
|
|
34
|
+
const size = fs.fstatSync(fd).size;
|
|
35
|
+
const chunk_size = Math.min(size, 4096);
|
|
36
|
+
const buf = Buffer.alloc(chunk_size);
|
|
37
|
+
fs.readSync(fd, buf, 0, chunk_size, size - chunk_size);
|
|
38
|
+
tail = _utf8Replace(buf);
|
|
39
|
+
} finally {
|
|
40
|
+
fs.closeSync(fd);
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const lines = tail.split('\n');
|
|
46
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
47
|
+
const line = (lines[i] as string).trim();
|
|
48
|
+
if (!line) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const event = parse_event(`${line}\n`);
|
|
53
|
+
return event.ts;
|
|
54
|
+
} catch (exc) {
|
|
55
|
+
if (exc instanceof EngagementSchemaError) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
throw exc;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Decode UTF-8 with replacement (Python `errors="replace"`). */
|
|
65
|
+
function _utf8Replace(buf: Buffer): string {
|
|
66
|
+
return new TextDecoder('utf-8', { fatal: false }).decode(buf);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface LogStats {
|
|
70
|
+
exists: boolean;
|
|
71
|
+
size_bytes?: number;
|
|
72
|
+
line_count?: number;
|
|
73
|
+
error?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function _log_stats(log_path: string): LogStats {
|
|
77
|
+
if (!_isFile(log_path)) {
|
|
78
|
+
return { exists: false, size_bytes: 0, line_count: 0 };
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const size = fs.statSync(log_path).size;
|
|
82
|
+
const buf = fs.readFileSync(log_path);
|
|
83
|
+
let line_count = 0;
|
|
84
|
+
for (const b of buf) {
|
|
85
|
+
if (b === 0x0a) {
|
|
86
|
+
line_count += 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Python `sum(1 for _ in fh)` counts lines: a final line without a
|
|
90
|
+
// trailing newline still counts. Match `open(..,"rb")` iteration.
|
|
91
|
+
if (buf.length > 0 && buf[buf.length - 1] !== 0x0a) {
|
|
92
|
+
line_count += 1;
|
|
93
|
+
}
|
|
94
|
+
return { exists: true, size_bytes: size, line_count };
|
|
95
|
+
} catch (exc) {
|
|
96
|
+
return { exists: true, error: _osErr(exc) };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
interface Report {
|
|
101
|
+
enabled: boolean;
|
|
102
|
+
section_present: boolean;
|
|
103
|
+
granularity: string;
|
|
104
|
+
record: { consulted: boolean; applied: boolean };
|
|
105
|
+
log: Record<string, unknown>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function _build_report(settings: TelemetrySettings): Report {
|
|
109
|
+
const log_path = settings.log_path;
|
|
110
|
+
const stats = _log_stats(log_path);
|
|
111
|
+
const log: Record<string, unknown> = {
|
|
112
|
+
path: log_path,
|
|
113
|
+
...stats,
|
|
114
|
+
last_event_ts: _last_event_ts(log_path),
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
enabled: settings.enabled,
|
|
118
|
+
section_present: settings.section_present,
|
|
119
|
+
granularity: settings.granularity,
|
|
120
|
+
record: {
|
|
121
|
+
consulted: settings.record_consulted,
|
|
122
|
+
applied: settings.record_applied,
|
|
123
|
+
},
|
|
124
|
+
log,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function _render_text(report: Report): string {
|
|
129
|
+
const lines: string[] = [];
|
|
130
|
+
let enabled = report.enabled ? '✅ enabled' : '⛔ disabled';
|
|
131
|
+
if (!report.section_present) {
|
|
132
|
+
enabled += ' (no telemetry section in .agent-settings.yml — using defaults)';
|
|
133
|
+
}
|
|
134
|
+
lines.push(` artifact-engagement: ${enabled}`);
|
|
135
|
+
lines.push(` granularity: ${report.granularity}`);
|
|
136
|
+
const rec = report.record;
|
|
137
|
+
lines.push(
|
|
138
|
+
` record: consulted=${_pyBool(rec.consulted)} `
|
|
139
|
+
+ `applied=${_pyBool(rec.applied)}`,
|
|
140
|
+
);
|
|
141
|
+
const log = report.log;
|
|
142
|
+
lines.push(` log path: ${log['path'] as string}`);
|
|
143
|
+
if (log['exists']) {
|
|
144
|
+
if ('error' in log && log['error'] !== undefined) {
|
|
145
|
+
lines.push(` log error: ${log['error'] as string}`);
|
|
146
|
+
} else {
|
|
147
|
+
lines.push(
|
|
148
|
+
` log size: ${log['size_bytes'] as number} bytes `
|
|
149
|
+
+ `(${log['line_count'] as number} events)`,
|
|
150
|
+
);
|
|
151
|
+
if (log['last_event_ts']) {
|
|
152
|
+
lines.push(` last event ts: ${log['last_event_ts'] as string}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
lines.push(' log: not yet created');
|
|
157
|
+
}
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Python `str(bool)` → `True` / `False` (f-string of a bool). */
|
|
162
|
+
function _pyBool(b: boolean): string {
|
|
163
|
+
return b ? 'True' : 'False';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
interface StatusArgs {
|
|
167
|
+
format: string;
|
|
168
|
+
settings: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
class ArgError extends Error {}
|
|
172
|
+
|
|
173
|
+
function _reprStr(s: string): string {
|
|
174
|
+
return `'${s}'`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function _parseArgs(argv: string[]): StatusArgs {
|
|
178
|
+
const a: StatusArgs = { format: 'text', settings: '.agent-settings.yml' };
|
|
179
|
+
const formatChoices = ['text', 'json'];
|
|
180
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
181
|
+
let tok = argv[i] as string;
|
|
182
|
+
let inlineVal: string | null = null;
|
|
183
|
+
const eq = tok.indexOf('=');
|
|
184
|
+
if (tok.startsWith('--') && eq !== -1) {
|
|
185
|
+
inlineVal = tok.slice(eq + 1);
|
|
186
|
+
tok = tok.slice(0, eq);
|
|
187
|
+
}
|
|
188
|
+
const next = (): string => {
|
|
189
|
+
if (inlineVal !== null) {
|
|
190
|
+
return inlineVal;
|
|
191
|
+
}
|
|
192
|
+
i += 1;
|
|
193
|
+
return argv[i] as string;
|
|
194
|
+
};
|
|
195
|
+
if (tok === '--format') {
|
|
196
|
+
const v = next();
|
|
197
|
+
if (!formatChoices.includes(v)) {
|
|
198
|
+
throw new ArgError(
|
|
199
|
+
`argument --format: invalid choice: ${_reprStr(v)} `
|
|
200
|
+
+ `(choose from ${formatChoices.map(_reprStr).join(', ')})`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
a.format = v;
|
|
204
|
+
} else if (tok === '--settings') a.settings = next();
|
|
205
|
+
else throw new ArgError(`unrecognized arguments: ${argv[i]}`);
|
|
206
|
+
}
|
|
207
|
+
return a;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function main(argv: string[] = process.argv.slice(2)): number {
|
|
211
|
+
let args: StatusArgs;
|
|
212
|
+
try {
|
|
213
|
+
args = _parseArgs(argv);
|
|
214
|
+
} catch (exc) {
|
|
215
|
+
if (exc instanceof ArgError) {
|
|
216
|
+
process.stderr.write(`error: ${exc.message}\n`);
|
|
217
|
+
return 2;
|
|
218
|
+
}
|
|
219
|
+
throw exc;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
let settings: TelemetrySettings;
|
|
223
|
+
try {
|
|
224
|
+
settings = read_settings(args.settings);
|
|
225
|
+
} catch (exc) {
|
|
226
|
+
process.stderr.write(`❌ cannot read settings: ${_osErr(exc)}\n`);
|
|
227
|
+
return 2;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const report = _build_report(settings);
|
|
231
|
+
if (args.format === 'json') {
|
|
232
|
+
// print(json.dumps(report, sort_keys=True, indent=2)) → +trailing \n
|
|
233
|
+
process.stdout.write(`${_py_json_dumps_indent2_sorted(report)}\n`);
|
|
234
|
+
} else {
|
|
235
|
+
process.stdout.write(`${_render_text(report)}\n`);
|
|
236
|
+
}
|
|
237
|
+
return 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function _osErr(exc: unknown): string {
|
|
241
|
+
return exc instanceof Error ? exc.message : String(exc);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// ── Python-parity JSON (indent=2, sorted keys) ──────────────────────────
|
|
245
|
+
|
|
246
|
+
function _py_json_dumps_indent2_sorted(value: unknown): string {
|
|
247
|
+
return _dumpIndent2(value, 0);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function _dumpIndent2(value: unknown, depth: number): string {
|
|
251
|
+
if (value === null || value === undefined) {
|
|
252
|
+
return 'null';
|
|
253
|
+
}
|
|
254
|
+
if (typeof value === 'boolean') {
|
|
255
|
+
return value ? 'true' : 'false';
|
|
256
|
+
}
|
|
257
|
+
if (typeof value === 'number') {
|
|
258
|
+
return Number.isInteger(value) ? String(value) : String(value);
|
|
259
|
+
}
|
|
260
|
+
if (typeof value === 'string') {
|
|
261
|
+
return _pyJsonStringAscii(value);
|
|
262
|
+
}
|
|
263
|
+
const pad = ' '.repeat(depth + 1);
|
|
264
|
+
const closePad = ' '.repeat(depth);
|
|
265
|
+
if (Array.isArray(value)) {
|
|
266
|
+
if (value.length === 0) {
|
|
267
|
+
return '[]';
|
|
268
|
+
}
|
|
269
|
+
const items = value.map((v) => pad + _dumpIndent2(v, depth + 1));
|
|
270
|
+
return `[\n${items.join(',\n')}\n${closePad}]`;
|
|
271
|
+
}
|
|
272
|
+
const obj = value as Record<string, unknown>;
|
|
273
|
+
const keys = Object.keys(obj).sort((a, b) => (a < b ? -1 : (a > b ? 1 : 0)));
|
|
274
|
+
if (keys.length === 0) {
|
|
275
|
+
return '{}';
|
|
276
|
+
}
|
|
277
|
+
const items = keys.map(
|
|
278
|
+
(k) => `${pad}${_pyJsonStringAscii(k)}: ${_dumpIndent2(obj[k], depth + 1)}`,
|
|
279
|
+
);
|
|
280
|
+
return `{\n${items.join(',\n')}\n${closePad}}`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function _pyJsonStringAscii(s: string): string {
|
|
284
|
+
let out = '"';
|
|
285
|
+
for (const ch of s) {
|
|
286
|
+
const code = ch.codePointAt(0) as number;
|
|
287
|
+
if (ch === '"') out += '\\"';
|
|
288
|
+
else if (ch === '\\') out += '\\\\';
|
|
289
|
+
else if (ch === '\n') out += '\\n';
|
|
290
|
+
else if (ch === '\r') out += '\\r';
|
|
291
|
+
else if (ch === '\t') out += '\\t';
|
|
292
|
+
else if (ch === '\b') out += '\\b';
|
|
293
|
+
else if (ch === '\f') out += '\\f';
|
|
294
|
+
else if (code < 0x20) out += `\\u${code.toString(16).padStart(4, '0')}`;
|
|
295
|
+
else if (code < 0x7f) out += ch;
|
|
296
|
+
else if (code <= 0xffff) out += `\\u${code.toString(16).padStart(4, '0')}`;
|
|
297
|
+
else {
|
|
298
|
+
const c = code - 0x10000;
|
|
299
|
+
const hi = 0xd800 + (c >> 10);
|
|
300
|
+
const lo = 0xdc00 + (c & 0x3ff);
|
|
301
|
+
out += `\\u${hi.toString(16).padStart(4, '0')}\\u${lo.toString(16).padStart(4, '0')}`;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return `${out}"`;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function _isCliEntry(): boolean {
|
|
308
|
+
if (process.argv[1] === undefined) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
|
|
312
|
+
if (import.meta.url === argvUrl) {
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
// A symlinked invocation (e.g. via an installed `.augment/` projection,
|
|
316
|
+
// or macOS /var → /private/var temp dirs) makes the raw URLs differ:
|
|
317
|
+
// import.meta.url is the resolved real path while argv[1] keeps the
|
|
318
|
+
// symlink path. Compare realpaths so the entry guard still fires
|
|
319
|
+
// (without this the CLI silently no-ops when run through a symlink).
|
|
320
|
+
try {
|
|
321
|
+
const here = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
322
|
+
const argv = fs.realpathSync(path.resolve(process.argv[1]));
|
|
323
|
+
return here === argv;
|
|
324
|
+
} catch {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const _invokedDirectly =
|
|
330
|
+
_isCliEntry();
|
|
331
|
+
if (_invokedDirectly) {
|
|
332
|
+
process.exitCode = main();
|
|
333
|
+
}
|