7.8 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-generators | 04 | execute | 2 |
|
|
true |
|
|
Purpose: DEPL-03. RMM script is structurally similar to the Intune install script but has no separate detection artifact, no Intune packaging constraints, and explicitly uses $ErrorActionPreference = 'Stop' (RMM platforms surface exit codes, not STDERR). Output: src/generators/rmm-script.ts with all rmm-script.test.ts assertions green.
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/ROADMAP.md @.planning/phases/02-generators/02-01-SUMMARY.md @.planning/phases/02-generators/02-03-SUMMARY.md @src/store/types.ts @src/generators/ps-helpers.ts @src/generators/rmm-script.test.tsFrom src/generators/ps-helpers.ts (created in Plan 03):
export const CONFIG_DIR: Record<'machine-wide' | 'user-profile', string> = {
'machine-wide': 'C:\\ProgramData\\rclone',
'user-profile': '%APPDATA%\\rclone',
};
export function buildRcloneInstallBlock(installPath: string): string;
// Returns PowerShell snippet with Invoke-WebRequest -UseBasicParsing and zip extraction.
// Returns empty string if called conditionally — caller decides whether to include.
From src/store/types.ts:
export interface WizardState {
remote: { name: string; backendType: BackendType | null; params: Record<string, string> };
deployment: {
includeInstall: boolean;
configPath: 'machine-wide' | 'user-profile';
scriptTargets: ('intune' | 'rmm')[];
};
}
Key difference from Intune install:
- RMM scripts DO use $ErrorActionPreference = 'Stop' (RMM platforms capture exit codes; no STDERR-breaks-detection contract)
- No exit 0 / exit 1 convention required (but including for clarity is fine)
- No separate detection script — the RMM platform handles existence checks natively
```typescript
import type { WizardState } from '../store/types';
import { CONFIG_DIR, buildRcloneInstallBlock } from './ps-helpers';
export function buildRmmScript(state: WizardState): string {
const configDir = CONFIG_DIR[state.deployment.configPath];
const confContent = buildRcloneConfContent(state);
const installBlock = state.deployment.includeInstall
? buildRcloneInstallBlock(configDir)
: '';
return [
`# RMM Deployment Script — compatible with NinjaRMM, Datto, ConnectWise`,
`# Runs as SYSTEM. Idempotent (safe to re-run).`,
`$ErrorActionPreference = 'Stop'`,
``,
`$configDir = '${configDir}'`,
`$configPath = "$configDir\\rclone.conf"`,
``,
`# Idempotent: create directory if it doesn't exist`,
`if (-not (Test-Path $configDir)) {`,
` New-Item -ItemType Directory -Path $configDir -Force | Out-Null`,
`}`,
``,
`# Write config using UTF-8 no-BOM encoding`,
`# Note: Set-Content -Encoding UTF8 in PS 5.1 writes UTF-8 WITH BOM — do not use`,
`$confContent = @'`,
confContent.trimEnd(),
`'@`,
`[System.IO.File]::WriteAllText($configPath, $confContent, [System.Text.UTF8Encoding]::new($false))`,
installBlock,
``,
`exit 0`,
].join('\n') + '\n';
}
function buildRcloneConfContent(state: WizardState): string {
const RCLONE_TYPE_MAP: Record<string, string> = {
azureblob: 'azureblob',
s3: 's3',
's3-compatible': 's3',
};
const { name, backendType, params } = state.remote;
const rcloneType = backendType ? RCLONE_TYPE_MAP[backendType] : 'unknown';
const lines: string[] = [`[${name}]`, `type = ${rcloneType}`];
for (const [key, value] of Object.entries(params)) {
if (value !== '') lines.push(`${key} = ${value}`);
}
return lines.join('\n') + '\n';
}
```
Note: The buildRcloneConfContent helper is duplicated from intune-install.ts intentionally — both files are self-contained. If this feels wrong, the alternative is to import buildRcloneConf from './rclone-conf', which is also fine (no circular dependency). Use whichever approach keeps the code clear. Either satisfies the tests.
Anti-patterns to avoid:
- Do NOT use 'Write-Error' or 'Write-Host' for logging (leaks to STDERR / logs)
- Do NOT interpolate credential values in the here-string using PowerShell variables
- Do NOT use 'Set-Content -Encoding UTF8' (writes BOM in PS 5.1)
<success_criteria> DEPL-03: RMM script is self-contained, idempotent, runs correctly in a generic SYSTEM context. DEPL-04: includeInstall toggle adds/removes rclone download block in RMM script. DEPL-05: configPath correctly maps to C:\ProgramData\rclone or %APPDATA%\rclone in RMM script. Phase 2 is complete: all six requirements (CONF-01, DEPL-01 through DEPL-05) have green unit tests. </success_criteria>
After completion, create `.planning/phases/02-generators/02-04-SUMMARY.md`