fix: support device-pod filename rg
This commit is contained in:
@@ -120,12 +120,18 @@ host `logTail` + `buildSummary` directly through the formal REST job path.
|
||||
### 3. `workspace rg --pattern "regex|pipes"` collides with local shell
|
||||
|
||||
When the regex contains `|` or other shell metacharacters, the local shell
|
||||
interprets them before `hwpod` sees the pattern. Two safe forms:
|
||||
interprets them before `hwpod` sees the pattern. `workspace rg` searches file
|
||||
contents by default; use `--name-only`, `--names`, or `--files-with-matches`
|
||||
when you need to match workspace-relative file names such as build artifacts.
|
||||
Safe forms:
|
||||
|
||||
```sh
|
||||
# shell-safe: pattern as one arg, but | still needs quoting
|
||||
hwpod <pod>:workspace:/ rg --pattern "Programming Done|Verify OK" --path <relpath>
|
||||
|
||||
# filename search for build artifacts
|
||||
hwpod <pod>:workspace:/ rg --pattern "FREQ_Controller_FW\\.(axf|bin|hex)$" --path projects/71-00075-11/FirmWare/MDK-ARM --name-only
|
||||
|
||||
# bullet-proof: pattern as base64
|
||||
P=$(printf "%s" "Error\(s\)|Warning\(s\)|Erase Done|Programming Done|Verify OK|Application running" | base64 -w0)
|
||||
hwpod <pod>:workspace:/ rg --pattern-b64 "$P" --path <relpath> --reason "log scan"
|
||||
@@ -171,6 +177,7 @@ Run read-only workspace, debug, and I/O jobs:
|
||||
hwpod device-pod-71-freq:workspace:/ ls
|
||||
hwpod device-pod-71-freq:workspace:/src rg main
|
||||
hwpod device-pod-71-freq:workspace:/ rg --pattern "Programming Done|Verify OK|Application running|Error" --path projects/01_baseline/captures
|
||||
hwpod device-pod-71-freq:workspace:/ rg --pattern "FREQ_Controller_FW\\.(axf|bin|hex)$" --path projects/71-00075-11/FirmWare/MDK-ARM --name-only
|
||||
hwpod device-pod-71-freq:debug-probe chip-id
|
||||
hwpod device-pod-71-freq:io-probe:/uart/1 read --duration-ms 5000
|
||||
```
|
||||
@@ -242,7 +249,7 @@ Do not treat local files such as `.device-pod/device-pod-71-freq.json` or `DEVIC
|
||||
- Use `hwpod`/`device-pod-cli` first for workspace, build, download, reset, UART, and debug-probe tasks.
|
||||
- After selecting a pod or resuming context, run `bootsharp --pod-id <devicePodId>` before edits, build, or download.
|
||||
- Prefer `workspace apply-patch` for source edits. Use `workspace put` only for intentional whole-file writes or new files, because it bypasses hunk-level conflict detection.
|
||||
- For regex searches with spaces, pipes, or multiple path tokens, prefer explicit `rg --pattern <regex> --path <workspaceRel>` or `--pattern-b64 <base64>` instead of positional shell parsing.
|
||||
- For regex searches with spaces, pipes, or multiple path tokens, prefer explicit `rg --pattern <regex> --path <workspaceRel>` or `--pattern-b64 <base64>` instead of positional shell parsing. `rg` searches file contents by default; add `--name-only` / `--names` / `--files-with-matches` to search file names, and `--limit <N>` to raise the file walk ceiling for large Keil workspaces.
|
||||
- If apply-patch fails, read the returned `patchHint`, re-read the current file with `workspace cat` or `workspace rg`, and retry a smaller exact-context hunk before using whole-file write.
|
||||
- Do not start by calling `/app/tools/hwlab-gateway-tran.mjs`, Windows-side Keil skills, serial-monitor skills, `keil-cli.py`, or generic shell when the Device Pod REST path is available.
|
||||
- If the CLI returns an auth, grant, lease, executor, or gateway blocker, fix that named blocker in the cloud-api/device-pod path; do not bypass the profile with generic gateway shell.
|
||||
|
||||
@@ -598,39 +598,48 @@ function workspaceRm(rel, options = {}) {
|
||||
ok('workspace.rm', { path: path.relative(profile.__workspaceRoot, file), removed: true, bytes: content.length, sha256: createHash('sha256').update(content).digest('hex') });
|
||||
}
|
||||
|
||||
function walkFiles(root, rel, results, limit = 5000) {
|
||||
if (results.length >= limit) return;
|
||||
function walkFiles(root, rel, results, limit = 20000) {
|
||||
if (results.length >= limit) return true;
|
||||
const dir = path.join(root, rel);
|
||||
let truncated = false;
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === '.state') continue;
|
||||
const childRel = path.join(rel, entry.name);
|
||||
if (entry.isDirectory()) walkFiles(root, childRel, results, limit);
|
||||
if (entry.isDirectory()) truncated = walkFiles(root, childRel, results, limit) || truncated;
|
||||
else if (entry.isFile()) results.push(childRel);
|
||||
if (results.length >= limit) return;
|
||||
if (results.length >= limit) return true;
|
||||
}
|
||||
return truncated;
|
||||
}
|
||||
|
||||
function rgWorkspace(pattern, rel, options = {}) {
|
||||
const profile = loadProfile();
|
||||
const root = resolveWorkspacePath(profile, rel || '.');
|
||||
const files = [];
|
||||
const scanLimit = parsePositiveInt(optionValue(options, 'limit'), 20000, 'rg limit', 1, 100000);
|
||||
let filesTruncated = false;
|
||||
const stat = fs.statSync(root);
|
||||
if (stat.isFile()) files.push(path.relative(profile.__workspaceRoot, root));
|
||||
else {
|
||||
const nested = [];
|
||||
const rootRel = path.relative(profile.__workspaceRoot, root) || '.';
|
||||
walkFiles(root, '.', nested);
|
||||
filesTruncated = walkFiles(root, '.', nested, scanLimit);
|
||||
files.push(...nested.map((fileRel) => rootRel === '.' ? fileRel : path.join(rootRel, fileRel)));
|
||||
}
|
||||
const re = new RegExp(pattern, 'i');
|
||||
const matches = [];
|
||||
const fileMatches = [];
|
||||
const filesWithMatches = Boolean(options.l || options.filesWithMatches || options['files-with-matches'] || options._?.includes('-l'));
|
||||
const nameOnly = Boolean(filesWithMatches || options.nameOnly || options['name-only'] || options.names || options._?.includes('--name-only'));
|
||||
const globs = normalizeList(options.g).concat(normalizeList(options.glob), normalizeList(options.iglob));
|
||||
const types = normalizeList(options.t).concat(normalizeList(options.type));
|
||||
for (const fileRel of files) {
|
||||
if (!rgFileAllowed(fileRel, { globs, types })) continue;
|
||||
if (!filesWithMatches && matches.length >= 100) break;
|
||||
if (nameOnly) {
|
||||
if (re.test(fileRel.replace(/\\/gu, '/'))) fileMatches.push(fileRel);
|
||||
continue;
|
||||
}
|
||||
if (matches.length >= 100) break;
|
||||
const full = resolveWorkspacePath(profile, fileRel);
|
||||
const buffer = fs.readFileSync(full);
|
||||
if (buffer.includes(0)) continue;
|
||||
@@ -645,7 +654,7 @@ function rgWorkspace(pattern, rel, options = {}) {
|
||||
if (matches.length < 100) matches.push({ path: fileRel, line: index + 1, text: line.slice(0, 500) });
|
||||
}
|
||||
}
|
||||
ok('workspace.rg', { pattern, root: path.relative(profile.__workspaceRoot, root) || '.', count: filesWithMatches ? fileMatches.length : matches.length, files: filesWithMatches ? fileMatches : undefined, matches: filesWithMatches ? undefined : matches, options: { globs, types, filesWithMatches } });
|
||||
ok('workspace.rg', { pattern, root: path.relative(profile.__workspaceRoot, root) || '.', count: nameOnly ? fileMatches.length : matches.length, files: nameOnly ? fileMatches : undefined, matches: nameOnly ? undefined : matches, options: { globs, types, filesWithMatches, nameOnly, scanLimit, filesScanned: files.length, filesTruncated } });
|
||||
}
|
||||
|
||||
function resolveRgWorkspaceRequest(rest) {
|
||||
@@ -654,7 +663,14 @@ function resolveRgWorkspaceRequest(rest) {
|
||||
if (encodedPattern !== undefined) {
|
||||
return {
|
||||
pattern: decodeBase64Utf8(encodedPattern, '--pattern-b64'),
|
||||
rel: parsed._[0] || '.',
|
||||
rel: optionString(parsed, 'path') || parsed._[0] || '.',
|
||||
options: parsed,
|
||||
};
|
||||
}
|
||||
if (parsed.pattern !== undefined) {
|
||||
return {
|
||||
pattern: String(Array.isArray(parsed.pattern) ? parsed.pattern[0] : parsed.pattern),
|
||||
rel: optionString(parsed, 'path') || parsed._[0] || '.',
|
||||
options: parsed,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user