@misterhuydo/sentinel 1.3.1 → 1.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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-03-23T17:39:48.232Z",
3
- "checkpoint_at": "2026-03-23T17:39:48.233Z",
2
+ "message": "Auto-checkpoint at 2026-03-23T17:56:42.485Z",
3
+ "checkpoint_at": "2026-03-23T17:56:42.486Z",
4
4
  "active_files": [],
5
5
  "notes": [],
6
6
  "mtime_snapshot": {}
package/lib/add.js CHANGED
@@ -364,6 +364,51 @@ async function addFromGit(gitUrl, workspace) {
364
364
  warn('AUTO_PUBLISH=true: fixes push directly to main. Ensure CI blocks bad pushes.');
365
365
  }
366
366
 
367
+ // ── GitHub token ───────────────────────────────────────────────────────────
368
+ // AUTO_PUBLISH=false → required (open PRs via API)
369
+ // AUTO_PUBLISH=true → optional (CI/CD triggers only)
370
+ const workspaceProps = path.join(workspace, 'sentinel.properties');
371
+ const existingToken = fs.existsSync(workspaceProps)
372
+ ? (fs.readFileSync(workspaceProps, 'utf8').match(/^GITHUB_TOKEN\s*=\s*(.+)$/m) || [])[1]?.trim()
373
+ : '';
374
+
375
+ if (!autoPublish) {
376
+ // PR mode — token is required
377
+ console.log('');
378
+ console.log(chalk.bold(' GitHub Personal Access Token (classic) — required for opening PRs'));
379
+ console.log(chalk.cyan(' github.com/settings/tokens/new → Tokens (classic)'));
380
+ console.log(chalk.cyan(' Note: "Expiration → No expiration" Scope: ✓ repo'));
381
+ console.log('');
382
+ }
383
+
384
+ const { githubToken } = await prompts({
385
+ type: (!autoPublish || !existingToken) ? 'password' : null,
386
+ name: 'githubToken',
387
+ message: existingToken
388
+ ? 'GitHub token (press Enter to keep current)'
389
+ : autoPublish
390
+ ? 'GitHub token (classic, repo scope) — optional, press Enter to skip'
391
+ : 'GitHub token (classic, repo scope)',
392
+ validate: v => {
393
+ if (!autoPublish && !v && !existingToken) return 'Token is required for PR mode';
394
+ if (v && !v.startsWith('ghp_') && !v.startsWith('github_pat_')) return 'Should start with ghp_ or github_pat_';
395
+ return true;
396
+ },
397
+ }, { onCancel: () => process.exit(0) });
398
+
399
+ const effectiveToken = githubToken || existingToken || '';
400
+ if (effectiveToken && fs.existsSync(workspaceProps)) {
401
+ let props = fs.readFileSync(workspaceProps, 'utf8');
402
+ if (/^#?\s*GITHUB_TOKEN\s*=/m.test(props))
403
+ props = props.replace(/^#?\s*GITHUB_TOKEN\s*=.*/m, `GITHUB_TOKEN=${effectiveToken}`);
404
+ else
405
+ props = props.trimEnd() + `\nGITHUB_TOKEN=${effectiveToken}\n`;
406
+ fs.writeFileSync(workspaceProps, props);
407
+ ok('GITHUB_TOKEN saved to workspace sentinel.properties');
408
+ } else if (effectiveToken) {
409
+ info('GITHUB_TOKEN will be written when project files are created');
410
+ }
411
+
367
412
  // ── Preview + confirm ──────────────────────────────────────────────────────
368
413
  const projectDir = path.join(workspace, name);
369
414
 
@@ -426,7 +471,7 @@ async function addFromGit(gitUrl, workspace) {
426
471
  });
427
472
  const example = path.join(repoDir, '_example.properties');
428
473
  if (fs.existsSync(example)) fs.removeSync(example);
429
- generateWorkspaceScripts(workspace);
474
+ generateWorkspaceScripts(workspace, {}, {}, {}, effectiveToken);
430
475
  ok(`Project "${name}" created at ${projectDir}`);
431
476
  printNextSteps(projectDir, autoPublish);
432
477
  }
package/lib/generate.js CHANGED
@@ -96,7 +96,7 @@ rm -f "$PID_FILE"
96
96
 
97
97
  // ── Workspace-level startAll / stopAll ────────────────────────────────────────
98
98
 
99
- function generateWorkspaceScripts(workspace, smtpConfig = {}, slackConfig = {}, authConfig = {}) {
99
+ function generateWorkspaceScripts(workspace, smtpConfig = {}, slackConfig = {}, authConfig = {}, githubToken = '') {
100
100
  // Write shared sentinel.properties once (never overwrite existing)
101
101
  const workspaceProps = path.join(workspace, 'sentinel.properties');
102
102
  if (!fs.existsSync(workspaceProps)) {
@@ -126,6 +126,15 @@ function generateWorkspaceScripts(workspace, smtpConfig = {}, slackConfig = {},
126
126
  }
127
127
  fs.writeFileSync(workspaceProps, props);
128
128
  }
129
+ // Always upsert GitHub token so re-runs persist it
130
+ if (githubToken) {
131
+ let props = fs.readFileSync(workspaceProps, 'utf8');
132
+ if (/^#?\s*GITHUB_TOKEN=/m.test(props))
133
+ props = props.replace(/^#?\s*GITHUB_TOKEN=.*/mg, 'GITHUB_TOKEN=' + githubToken);
134
+ else
135
+ props = props.trimEnd() + '\nGITHUB_TOKEN=' + githubToken + '\n';
136
+ fs.writeFileSync(workspaceProps, props);
137
+ }
129
138
  // Always upsert Slack tokens so re-runs persist them
130
139
  if (slackConfig.botToken || slackConfig.appToken) {
131
140
  let props = fs.readFileSync(workspaceProps, 'utf8');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"