@6reduk/workspace-pipeline 0.3.0 → 0.4.0

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 CHANGED
@@ -52,7 +52,9 @@ npm run pack:check
52
52
  npm run test:packed:providers
53
53
  ```
54
54
 
55
- The executable name is `workspace-pipeline`. Doctor prints JSON: exit 0 means
55
+ The executable name is `workspace-pipeline`. Output is readable by default;
56
+ add `--json` for complete machine output. Use `--json` when saving any preview
57
+ for a later apply, even when redirecting stdout to a file. Doctor exit 0 means
56
58
  observed configuration ready, 1 means not ready/incomplete, 2 means invocation or
57
59
  transport error. Unsupported commands exit with code 2. On Windows use an absolute
58
60
  path such as `C:\Projects\my-workspace`. See [doctor](docs/doctor.md) for limits.
package/docs/doctor.md CHANGED
@@ -5,7 +5,8 @@ The public CLI exposes it read-only:
5
5
 
6
6
  `workspace-pipeline doctor --workspace <absolute-path> [--recovery <relative-record>] [--json]`
7
7
 
8
- Output is JSON even without --json. Exit 0 means configuration ready, 1 not ready
8
+ Output is a readable status summary by default. `--json` returns the complete
9
+ machine report (including every target/hash). Exit 0 means configuration ready, 1 not ready
9
10
  or incomplete, 2 invalid invocation or output failure. This is not an install command.
10
11
 
11
12
  `ready` means observed **configuration readiness**, never a running harness,
package/docs/launch.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Scoped Grok launch (S11 development)
2
2
 
3
+ ## Configuration limitation (checked 2026-09-23)
4
+
5
+ The desired UX is ordinary `grok` with workspace-local compatibility settings,
6
+ not a mandatory launcher. This is currently blocked by the harness: installed
7
+ Grok 1.0.40 and the upstream configuration reference list only `mcp_servers`,
8
+ `plugins`, `permission`, and `mcp.max_output_bytes` as project config inputs.
9
+ `compat.claude` is not among them. Writing five false values locally must not be
10
+ represented as working import suppression. The CLI does not change user-wide
11
+ compat settings as a substitute. The legacy launch route below remains an
12
+ explicit workaround, not the approved long-term configuration model.
13
+
14
+ Source: [Grok configuration reference](https://github.com/xai-org/grok-build/blob/main/crates/codegen/xai-grok-pager/docs/user-guide/26-config-reference.md),
15
+ configuration layers and `compat` fields. No new live-isolation claim is made.
16
+
3
17
  This command starts Grok from an already configured workspace with five Claude
4
18
  compatibility switches set to false in the child environment: skills, rules, agents,
5
19
  MCP and hooks. It does not install a pipeline. Configure Grok using the ordinary
@@ -23,7 +23,8 @@ workspace-pipeline setup --workspace <absolute-wrapper> --apply --preview <absol
23
23
  workspace-pipeline update --workspace <absolute-wrapper> --apply --preview <absolute-json-file>
24
24
  ```
25
25
 
26
- Preview returns the complete prepared JSON on stdout. It may acquire a Git
26
+ Preview displays a human-readable summary by default. Add `--json` to return
27
+ the complete prepared JSON on stdout for saving and subsequent apply. It may acquire a Git
27
28
  source into temporary storage outside the wrapper, but does not write provider
28
29
  configuration. Network acquisition requires explicit `--network`. When manifest
29
30
  is omitted, setup uses the standard workspace manifest; update uses the recorded
@@ -68,7 +69,7 @@ restoration; empty reset must be explicitly selected.
68
69
 
69
70
  ## Output and failures
70
71
 
71
- - stdout: one prepared JSON or operation result.
72
+ - stdout: readable result by default; with `--json`, one complete prepared JSON or operation result.
72
73
  - stderr during apply: structured journal/recovery locations and operation events.
73
74
  - exit 0: preview created, or observed configuration ready with successful lock
74
75
  release and reporting. It never certifies harness/MCP runtime.
package/docs/rebind.md CHANGED
@@ -15,8 +15,8 @@ The following PowerShell example uses illustrative absolute paths; replace them.
15
15
  Use a private directory for preview files: they can contain configuration values.
16
16
 
17
17
  ```powershell
18
- workspace-pipeline rebind --workspace 'C:\Work\Game' --manifest 'C:\Work\Game\workspace.json' > 'C:\Private\rebind.json'
19
- workspace-pipeline update --workspace 'C:\Work\Game' --accept-rebind 'C:\Private\rebind.json' > 'C:\Private\update.json'
18
+ workspace-pipeline rebind --workspace 'C:\Work\Game' --manifest 'C:\Work\Game\workspace.json' --json > 'C:\Private\rebind.json'
19
+ workspace-pipeline update --workspace 'C:\Work\Game' --accept-rebind 'C:\Private\rebind.json' --json > 'C:\Private\update.json'
20
20
  workspace-pipeline update --workspace 'C:\Work\Game' --apply --preview 'C:\Private\update.json'
21
21
  workspace-pipeline doctor --workspace 'C:\Work\Game'
22
22
  ```
@@ -27,7 +27,7 @@ commit, not uncommitted files of its source.
27
27
  workspace-pipeline wrap --workspace "C:\Work\GameWorkspace" --manifest "C:\Work\workspace.json" --choices "C:\Work\choices.json"
28
28
  ```
29
29
 
30
- Save the exact JSON stdout as UTF-8 `preview.json` outside the affected repository
30
+ Use `--json` and save the exact JSON stdout as UTF-8 `preview.json` outside the affected repository
31
31
  and wrapper. Read its operations and blockers. Preview may acquire a temporary
32
32
  Git snapshot, but does not perform repository effects. Remote access is explicit
33
33
  with `--network`; local Git does not need that flag. Do not put credentials into
@@ -39,8 +39,8 @@ delete pending markers or lock directories to make `doctor` report success.
39
39
 
40
40
  `no-pending-marker` means exactly that; it does not certify historical completion,
41
41
  provider readiness or game runtime. A blocker means further recovery is needed;
42
- this command never grants itself authority to resolve it. `--json` is redundant
43
- but accepted because JSON is already the default output.
42
+ this command never grants itself authority to resolve it. Add `--json` for
43
+ machine-readable output and whenever saving a preview for apply.
44
44
 
45
45
  ## Local recovery ownership
46
46
 
package/docs/reset.md CHANGED
@@ -13,7 +13,7 @@ Close running harnesses/configuration editors. Keep preview files private: they
13
13
  contain before/after bytes, potentially including MCP credentials.
14
14
 
15
15
  ```powershell
16
- workspace-pipeline reset --workspace 'C:\Work\Game' --all > 'C:\Private\reset.json'
16
+ workspace-pipeline reset --workspace 'C:\Work\Game' --all --json > 'C:\Private\reset.json'
17
17
  # Check $LASTEXITCODE and review reset.scope, reset.backup and preview.plan.targets.
18
18
  workspace-pipeline reset --workspace 'C:\Work\Game' --apply --preview 'C:\Private\reset.json'
19
19
  workspace-pipeline doctor --workspace 'C:\Work\Game'
package/docs/retention.md CHANGED
@@ -75,7 +75,8 @@ check has cost proportional to selected files times retained records, bounded by
75
75
  scan limits and the user deletion cap. It is not a linear-cost guarantee or an
76
76
  OS-wide defense against hostile concurrent filesystem writers.
77
77
 
78
- Progress is emitted as JSON on stderr; final JSON is on stdout. The receipt path
78
+ With `--json`, progress is emitted as JSON on stderr and final JSON on stdout;
79
+ otherwise both are formatted for reading. Save apply previews using `--json`. The receipt path
79
80
  is under `.pipeline/cleanup/<run-id>.json`. Receipts record selected file hashes,
80
81
  confirmed deletions, reclaimed bytes, current intent and failures. These receipts
81
82
  describe attempted/deleted paths; unlike operational recovery records, they are
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@6reduk/workspace-pipeline",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Workspace-local Git pipeline configuration dispatcher",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {runCli} from './commands/dispatch.js';
3
3
  import {providerRegistry} from './providers/registry.js';
4
+ import {outputWriter} from './commands/output.js';
4
5
  const write=stream=>text=>new Promise((resolve,reject)=>stream.write(text,error=>error?reject(error):resolve()));
5
6
  // Prevent an unhandled pipe error; write callbacks report delivery failures.
6
7
  process.stdout.on('error',()=>{});process.stderr.on('error',()=>{});
7
- process.exitCode=await runCli(process.argv.slice(2),{stdout:write(process.stdout),stderr:write(process.stderr),registry:providerRegistry});
8
+ const args=process.argv.slice(2),json=args.includes('--json');
9
+ process.exitCode=await runCli(args,{stdout:outputWriter(write(process.stdout),json),stderr:outputWriter(write(process.stderr),json),registry:providerRegistry});
@@ -62,7 +62,9 @@ Preview stages Git externally; inspect is read-only/offline. JSON can contain
62
62
  private config bytes. Only explicit apply writes or clears a validated pending marker.
63
63
  Apply requires the saved installer-bound envelope and accepts no source overrides.
64
64
 
65
- Doctor is read-only and prints JSON. Exit 0 means observed configuration ready;
65
+ Output is human-readable by default; use --json for complete machine output.
66
+ Save previews for apply with --json (including when redirecting stdout).
67
+ Doctor is read-only. Exit 0 means observed configuration ready;
66
68
  exit 1 means not ready/incomplete; exit 2 means invalid invocation or unavailable command.
67
69
  Runtime, MCP/harness discovery and provider compatibility are NOT verified.
68
70
  No source access, automatic repair or lock removal. Read-only/configuration commands never clean history.
@@ -134,14 +136,14 @@ logs clean --repositories --workspace <absolute-directory> --max-age-days <N>
134
136
  Apply with --repositories --apply --preview <file>; this is a separate cleanup
135
137
  domain, never an implicit increase of the ordinary journal deletion budget.
136
138
  Execution inputs are retained privately under .pipeline/repository-inputs;
137
- --json is optional because JSON is the default.
139
+ --json selects the complete machine-readable result without presentation changes.
138
140
  This package is not ready to replace an existing installation.`;
139
141
 
140
142
  // Parse strictly before any filesystem observation. Never echo unknown arguments
141
143
  // (which can contain credentials). Output transport is trusted CLI code.
142
144
  export function parseCommand(args) {
143
145
  if(!Array.isArray(args) || args.some(a=>typeof a!=='string')) fail('cli.arguments');
144
- if(args.length===0 || (args.length===1 && ['--help','-h'].includes(args[0])))return {command:'help'};
146
+ if(args.length===0 || (['--help','-h'].includes(args[0]) && (args.length===1 || (args.length===2 && args[1]==='--json'))))return {command:'help'};
145
147
  if(args[0]==='launch')return parseLaunch(args);
146
148
  if(args[0]==='rebind')return parseRebind(args);
147
149
  if(args[0]==='reset')return parseReset(args);
@@ -11,8 +11,9 @@ export function parseLaunch(args) {
11
11
  const result = { command: 'launch', provider: 'grok', execute: false, inspect: false }, seen = new Set();
12
12
  for (let i = 2; i < args.length; i++) {
13
13
  const flag = args[i];
14
- if (!['--workspace', '--executable', '--execute', '--inspect'].includes(flag) || seen.has(flag)) fail('cli.arguments');
14
+ if (!['--workspace', '--executable', '--execute', '--inspect', '--json'].includes(flag) || seen.has(flag)) fail('cli.arguments');
15
15
  seen.add(flag);
16
+ if (flag === '--json') continue;
16
17
  if (flag === '--execute') { result.execute = true; continue; }
17
18
  if (flag === '--inspect') { result.inspect = true; continue; }
18
19
  const value = args[++i];
@@ -0,0 +1,46 @@
1
+ // Presentation boundary only: internal command results and saved JSON contracts
2
+ // remain unchanged. Never infer success from the shape of a rendered result.
3
+ const safe = value => String(value).replace(/[\u0000-\u001f\u007f-\u009f]/g, c => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`);
4
+ const privateKey = /bytes|base64|content|secret|token|password/i;
5
+
6
+ export function formatResult(value) {
7
+ if (value && typeof value.ready === 'boolean' && Array.isArray(value.diagnostics)) {
8
+ const lines = ['Workspace Pipeline — doctor', '',
9
+ `Workspace: ${safe(value.workspace ?? '(not reported)')}`,
10
+ `Status: ${value.ready ? 'READY' : 'NOT READY'} (${safe(value.status ?? 'unknown')})`];
11
+ if (value.pipeline) lines.push(`Pipeline: ${safe(value.pipeline.id)} @ ${safe(value.pipeline.version)}`,
12
+ `Providers: ${value.pipeline.providers.map(safe).join(', ')}`);
13
+ for (const key of ['configuration', 'transactionEvidence']) if (value[key] !== undefined) lines.push(`${key}: ${safe(value[key])}`);
14
+ lines.push('', `Diagnostics: ${value.diagnostics.length}`);
15
+ for (const item of value.diagnostics) lines.push(` - ${safe(item.code)}${item.subject ? ': ' + safe(item.subject) : ''}${item.pointer ? ' ' + safe(item.pointer) : ''}`);
16
+ lines.push('', 'Runtime / model-visible skills / MCP: not verified by doctor.',
17
+ 'Full report: repeat with --json.');
18
+ return lines.join('\n') + '\n';
19
+ }
20
+ const lines = ['Workspace Pipeline', ''];
21
+ function render(node, indent = '', depth = 0) {
22
+ if (node === null || typeof node !== 'object') { lines.push(indent + safe(node)); return; }
23
+ if (depth > 5) { lines.push(indent + '(details omitted; use --json)'); return; }
24
+ const entries = Object.entries(node);
25
+ for (const [key, item] of entries.slice(0, 40)) {
26
+ const label = indent + safe(key) + ':';
27
+ if (privateKey.test(key)) lines.push(label + ' (private payload; use --json)');
28
+ else if (item !== null && typeof item === 'object') { lines.push(label); render(item, indent + ' ', depth + 1); }
29
+ else { const text=safe(item); lines.push(label + ' ' + (text.length>500?text.slice(0,500)+' (truncated; use --json)':text)); }
30
+ }
31
+ if (entries.length > 40) lines.push(indent + `(${entries.length - 40} more entries; use --json)`);
32
+ }
33
+ render(value);
34
+ lines.push('', 'For complete machine output or a saved apply preview, repeat with --json.',
35
+ 'This display is not an apply preview. JSON may contain private configuration.');
36
+ return lines.join('\n') + '\n';
37
+ }
38
+
39
+ export function outputWriter(write, json) {
40
+ if (json) return write;
41
+ return text => {
42
+ let value;
43
+ try { value = JSON.parse(text); } catch { return write(text); }
44
+ return write(formatResult(value));
45
+ };
46
+ }
@@ -9,8 +9,9 @@ export function parseRebind(args) {
9
9
  const result={command:'rebind'},seen=new Set();
10
10
  for(let i=1;i<args.length;i++) {
11
11
  const flag=args[i];
12
- if(!['--workspace','--manifest'].includes(flag) || seen.has(flag))fail('cli.arguments');
12
+ if(!['--workspace','--manifest','--json'].includes(flag) || seen.has(flag))fail('cli.arguments');
13
13
  seen.add(flag);
14
+ if(flag==='--json')continue;
14
15
  const value=args[++i];if(!value || value.startsWith('--'))fail('cli.arguments');
15
16
  result[flag==='--workspace'?'workspace':'manifestPath']=absoluteRoot(value);
16
17
  }
@@ -11,8 +11,9 @@ export function parseReset(args){
11
11
  const result={command:'reset'},seen=new Set();
12
12
  for(let i=1;i<args.length;i++){
13
13
  const flag=args[i];
14
- if(!['--workspace','--to','--all','--providers','--bundles','--apply','--preview'].includes(flag) || seen.has(flag))fail('cli.arguments');
14
+ if(!['--workspace','--to','--all','--providers','--bundles','--apply','--preview','--json'].includes(flag) || seen.has(flag))fail('cli.arguments');
15
15
  seen.add(flag);
16
+ if(flag==='--json')continue;
16
17
  if(flag==='--apply'){result.apply=true;continue;}
17
18
  if(flag==='--all'){(result.options??={}).all=true;continue;}
18
19
  const value=args[++i];if(!value || value.startsWith('--'))fail('cli.arguments');