@thejoseki/clawform 2.3.1 → 2.3.2

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.
Files changed (48) hide show
  1. package/README.md +141 -120
  2. package/bin/clawform.js +161 -151
  3. package/package.json +65 -65
  4. package/src/aws/catalog.js +116 -116
  5. package/src/aws/changeset.js +231 -231
  6. package/src/aws/drift.js +59 -59
  7. package/src/aws/exports.js +213 -213
  8. package/src/aws/inventory.js +156 -156
  9. package/src/commands/activate.js +137 -105
  10. package/src/commands/ci-init.js +393 -212
  11. package/src/commands/cost-report.js +163 -163
  12. package/src/commands/deactivate.js +9 -2
  13. package/src/commands/deploy.js +413 -413
  14. package/src/commands/diff.js +39 -39
  15. package/src/commands/drift.js +35 -35
  16. package/src/commands/init-plugin.js +6 -6
  17. package/src/commands/init.js +360 -360
  18. package/src/commands/rollback.js +126 -126
  19. package/src/commands/status.js +147 -147
  20. package/src/commands/sync.js +50 -50
  21. package/src/commands/update.js +24 -0
  22. package/src/commands/validate.js +349 -349
  23. package/src/hooks/block-dangerous.js +62 -62
  24. package/src/hooks/cfn-lint-after-edit-eval.js +30 -30
  25. package/src/hooks/cfn-lint-after-edit.js +81 -81
  26. package/src/hooks/check-catalog-fresh-eval.js +63 -63
  27. package/src/hooks/check-catalog-fresh.js +33 -33
  28. package/src/hooks/session-context-eval.js +81 -81
  29. package/src/hooks/session-context.js +41 -41
  30. package/src/hooks/subagent-context-eval.js +44 -44
  31. package/src/hooks/subagent-context.js +48 -48
  32. package/src/lib/audit-synthesis.js +24 -24
  33. package/src/lib/aws-client.js +15 -15
  34. package/src/lib/cfn-yaml.js +92 -92
  35. package/src/lib/config.js +76 -76
  36. package/src/lib/constants.js +85 -85
  37. package/src/lib/defaults.js +16 -16
  38. package/src/lib/install-workflow.js +28 -28
  39. package/src/lib/kit-source.js +43 -5
  40. package/src/lib/license-client.js +84 -84
  41. package/src/lib/license-config.js +162 -162
  42. package/src/lib/license-store.js +43 -8
  43. package/src/lib/license.js +163 -150
  44. package/src/lib/lint-overrides.js +226 -226
  45. package/src/lib/logger.js +16 -16
  46. package/src/lib/project-config.js +145 -145
  47. package/src/lib/providers/polar.js +215 -215
  48. package/src/lib/session-state.js +91 -91
@@ -1,39 +1,39 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { existsSync } from 'node:fs';
3
- import { GetTemplateCommand } from '@aws-sdk/client-cloudformation';
4
- import { createPatch } from 'diff';
5
- import chalk from 'chalk';
6
- import { logger } from '../lib/logger.js';
7
- import { cfnClient } from '../lib/aws-client.js';
8
-
9
- export default async function diff({ stack, file }) {
10
- const localPath = file ?? `cfn/${stack}.yaml`;
11
- logger.step(`clawform diff ${stack} ↔ ${localPath}`);
12
-
13
- if (!existsSync(localPath)) {
14
- throw new Error(`Local template not found: ${localPath}. Pass --file <path> to override.`);
15
- }
16
- // Normalize line endings before comparison. CFN's GetTemplate returns LF, but
17
- // fs.readFile preserves whatever bytes are on disk — on Windows checkouts (git's
18
- // default core.autocrlf=true) every line of an identical template differs by a
19
- // trailing \r, producing a wall-of-red diff that destroys the command's value.
20
- const local = (await readFile(localPath, 'utf8')).replace(/\r\n/g, '\n');
21
-
22
- const client = cfnClient();
23
- const out = await client.send(new GetTemplateCommand({ StackName: stack, TemplateStage: 'Original' }));
24
- const live = (out.TemplateBody ?? '').replace(/\r\n/g, '\n');
25
-
26
- if (live === local) {
27
- logger.ok('No diff. Local template matches live stack.');
28
- return;
29
- }
30
-
31
- const patch = createPatch(stack, live, local, 'live', 'local', { context: 3 });
32
- for (const line of patch.split('\n')) {
33
- if (line.startsWith('+++ ') || line.startsWith('--- ')) console.log(chalk.bold(line));
34
- else if (line.startsWith('+')) console.log(chalk.green(line));
35
- else if (line.startsWith('-')) console.log(chalk.red(line));
36
- else if (line.startsWith('@@')) console.log(chalk.cyan(line));
37
- else console.log(line);
38
- }
39
- }
1
+ import { readFile } from 'node:fs/promises';
2
+ import { existsSync } from 'node:fs';
3
+ import { GetTemplateCommand } from '@aws-sdk/client-cloudformation';
4
+ import { createPatch } from 'diff';
5
+ import chalk from 'chalk';
6
+ import { logger } from '../lib/logger.js';
7
+ import { cfnClient } from '../lib/aws-client.js';
8
+
9
+ export default async function diff({ stack, file }) {
10
+ const localPath = file ?? `cfn/${stack}.yaml`;
11
+ logger.step(`clawform diff ${stack} ↔ ${localPath}`);
12
+
13
+ if (!existsSync(localPath)) {
14
+ throw new Error(`Local template not found: ${localPath}. Pass --file <path> to override.`);
15
+ }
16
+ // Normalize line endings before comparison. CFN's GetTemplate returns LF, but
17
+ // fs.readFile preserves whatever bytes are on disk — on Windows checkouts (git's
18
+ // default core.autocrlf=true) every line of an identical template differs by a
19
+ // trailing \r, producing a wall-of-red diff that destroys the command's value.
20
+ const local = (await readFile(localPath, 'utf8')).replace(/\r\n/g, '\n');
21
+
22
+ const client = cfnClient();
23
+ const out = await client.send(new GetTemplateCommand({ StackName: stack, TemplateStage: 'Original' }));
24
+ const live = (out.TemplateBody ?? '').replace(/\r\n/g, '\n');
25
+
26
+ if (live === local) {
27
+ logger.ok('No diff. Local template matches live stack.');
28
+ return;
29
+ }
30
+
31
+ const patch = createPatch(stack, live, local, 'live', 'local', { context: 3 });
32
+ for (const line of patch.split('\n')) {
33
+ if (line.startsWith('+++ ') || line.startsWith('--- ')) console.log(chalk.bold(line));
34
+ else if (line.startsWith('+')) console.log(chalk.green(line));
35
+ else if (line.startsWith('-')) console.log(chalk.red(line));
36
+ else if (line.startsWith('@@')) console.log(chalk.cyan(line));
37
+ else console.log(line);
38
+ }
39
+ }
@@ -1,35 +1,35 @@
1
- import chalk from 'chalk';
2
- import { logger } from '../lib/logger.js';
3
- import { cfnClient } from '../lib/aws-client.js';
4
- import { detectAndWait, listResourceDrifts } from '../aws/drift.js';
5
-
6
- export default async function drift({ stack }) {
7
- logger.step(`clawform drift ${stack}`);
8
- const client = cfnClient();
9
-
10
- logger.info('Detecting drift (this can take a few minutes)…');
11
- const summary = await detectAndWait(client, { stackName: stack });
12
- logger.info(`StackDriftStatus: ${summary.stackDriftStatus} · drifted resources: ${summary.driftedResourceCount}`);
13
-
14
- if (summary.stackDriftStatus === 'IN_SYNC') {
15
- logger.ok('No drift.');
16
- return;
17
- }
18
-
19
- const drifts = await listResourceDrifts(client, stack);
20
- for (const d of drifts) {
21
- logger.info('');
22
- logger.info(`${chalk.yellow(d.driftStatus)} ${d.logicalId} (${d.resourceType})`);
23
- for (const p of d.propertyDifferences) {
24
- const status = p.DifferenceType ?? '?';
25
- logger.info(` ${chalk.dim('@')}${p.PropertyPath ?? '/'} ${status}`);
26
- if (p.ExpectedValue !== undefined) logger.info(` expected: ${truncate(p.ExpectedValue)}`);
27
- if (p.ActualValue !== undefined) logger.info(` actual: ${truncate(p.ActualValue)}`);
28
- }
29
- }
30
- }
31
-
32
- function truncate(v, max = 120) {
33
- const s = typeof v === 'string' ? v : JSON.stringify(v);
34
- return s.length > max ? s.slice(0, max - 1) + '…' : s;
35
- }
1
+ import chalk from 'chalk';
2
+ import { logger } from '../lib/logger.js';
3
+ import { cfnClient } from '../lib/aws-client.js';
4
+ import { detectAndWait, listResourceDrifts } from '../aws/drift.js';
5
+
6
+ export default async function drift({ stack }) {
7
+ logger.step(`clawform drift ${stack}`);
8
+ const client = cfnClient();
9
+
10
+ logger.info('Detecting drift (this can take a few minutes)…');
11
+ const summary = await detectAndWait(client, { stackName: stack });
12
+ logger.info(`StackDriftStatus: ${summary.stackDriftStatus} · drifted resources: ${summary.driftedResourceCount}`);
13
+
14
+ if (summary.stackDriftStatus === 'IN_SYNC') {
15
+ logger.ok('No drift.');
16
+ return;
17
+ }
18
+
19
+ const drifts = await listResourceDrifts(client, stack);
20
+ for (const d of drifts) {
21
+ logger.info('');
22
+ logger.info(`${chalk.yellow(d.driftStatus)} ${d.logicalId} (${d.resourceType})`);
23
+ for (const p of d.propertyDifferences) {
24
+ const status = p.DifferenceType ?? '?';
25
+ logger.info(` ${chalk.dim('@')}${p.PropertyPath ?? '/'} ${status}`);
26
+ if (p.ExpectedValue !== undefined) logger.info(` expected: ${truncate(p.ExpectedValue)}`);
27
+ if (p.ActualValue !== undefined) logger.info(` actual: ${truncate(p.ActualValue)}`);
28
+ }
29
+ }
30
+ }
31
+
32
+ function truncate(v, max = 120) {
33
+ const s = typeof v === 'string' ? v : JSON.stringify(v);
34
+ return s.length > max ? s.slice(0, max - 1) + '…' : s;
35
+ }
@@ -115,7 +115,7 @@ export function assemblePlugin({ packageRoot, destDir, entries, licenseRecord, n
115
115
  return manifest;
116
116
  }
117
117
 
118
- export default async function initPlugin({ scope = 'global' } = {}, {
118
+ export default async function initPlugin({ scope = 'global', refresh = false } = {}, {
119
119
  packageRoot = PACKAGE_ROOT,
120
120
  homedir = osHomedir,
121
121
  client = resolveClient(),
@@ -137,16 +137,16 @@ export default async function initPlugin({ scope = 'global' } = {}, {
137
137
  licenseKey: readLicense()?.key,
138
138
  serviceUrl: KIT_SERVICE_URL,
139
139
  cacheDir: vendorHome,
140
+ refresh,
140
141
  });
141
142
 
142
143
  assemblePlugin({ packageRoot, destDir: pluginDir, entries, licenseRecord: readLicense() });
143
144
  log(`Plugin materialized at ${pluginDir}`);
144
145
 
145
- // Register with Claude Code. The exact marketplace/scope flags are Claude
146
- // Code semantics that must be confirmed against a live install (clean-room
147
- // C3) the runner is injected so this stays testable, and --project vs
148
- // --global is passed through for that verification.
149
- const scopeFlag = scope === 'project' ? ['--project'] : [];
146
+ // Register with Claude Code. Both subcommands take `--scope user|project|local`
147
+ // (default user); clawform "global" maps to user (all projects), "project" to
148
+ // project (./.claude). The runner is injected so this stays testable.
149
+ const scopeFlag = ['--scope', scope === 'project' ? 'project' : 'user'];
150
150
  const add = await runClaude(['plugin', 'marketplace', 'add', pluginDir, ...scopeFlag]);
151
151
  if (add.code !== 0) throw new Error(`claude plugin marketplace add failed: ${add.stderr ?? `exit ${add.code}`}`);
152
152
  const install = await runClaude(['plugin', 'install', 'clawform@clawform', ...scopeFlag]);