@misterhuydo/sentinel 1.4.81 → 1.4.82

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-27T02:09:31.962Z",
3
- "checkpoint_at": "2026-03-27T02:09:31.963Z",
2
+ "message": "Auto-checkpoint at 2026-03-27T02:10:14.448Z",
3
+ "checkpoint_at": "2026-03-27T02:10:14.449Z",
4
4
  "active_files": [],
5
5
  "notes": [],
6
6
  "mtime_snapshot": {}
package/lib/add.js CHANGED
@@ -616,23 +616,34 @@ async function addFromGit(gitUrl, workspace) {
616
616
  generateWorkspaceScripts(workspace, {}, {}, {}, effectiveToken);
617
617
  }
618
618
 
619
- // Write project-level Slack tokens if collected
619
+ // Write private Slack tokens to slack.properties (gitignored) + set PRIVATE_SLACK=true
620
620
  if (projectSlackBotToken || projectSlackAppToken) {
621
+ // Write slack.properties (never committed — tokens stay off git)
622
+ const slackProps = path.join(projectDir, 'slack.properties');
623
+ const lines = ['# Private Slack tokens for this project — DO NOT COMMIT'];
624
+ if (projectSlackBotToken) lines.push(`SLACK_BOT_TOKEN=${projectSlackBotToken}`);
625
+ if (projectSlackAppToken) lines.push(`SLACK_APP_TOKEN=${projectSlackAppToken}`);
626
+ fs.writeFileSync(slackProps, lines.join('\n') + '\n');
627
+ ok('Private Slack tokens → slack.properties (local only)');
628
+
629
+ // Ensure slack.properties is gitignored
630
+ const gitignore = path.join(projectDir, '.gitignore');
631
+ const ignoreEntry = 'slack.properties';
632
+ const existing = fs.existsSync(gitignore) ? fs.readFileSync(gitignore, 'utf8') : '';
633
+ if (!existing.includes(ignoreEntry)) {
634
+ fs.writeFileSync(gitignore, existing.trimEnd() + `\n${ignoreEntry}\n`);
635
+ ok('.gitignore updated — slack.properties will not be committed');
636
+ }
637
+
638
+ // Set PRIVATE_SLACK=true in config/sentinel.properties
621
639
  const projProps = path.join(projectDir, 'config', 'sentinel.properties');
622
640
  if (fs.existsSync(projProps)) {
623
641
  let props = fs.readFileSync(projProps, 'utf8');
624
- if (projectSlackBotToken) {
625
- props = /^#?\s*SLACK_BOT_TOKEN\s*=/m.test(props)
626
- ? props.replace(/^#?\s*SLACK_BOT_TOKEN\s*=.*/m, `SLACK_BOT_TOKEN=${projectSlackBotToken}`)
627
- : props.trimEnd() + `\nSLACK_BOT_TOKEN=${projectSlackBotToken}\n`;
628
- }
629
- if (projectSlackAppToken) {
630
- props = /^#?\s*SLACK_APP_TOKEN\s*=/m.test(props)
631
- ? props.replace(/^#?\s*SLACK_APP_TOKEN\s*=.*/m, `SLACK_APP_TOKEN=${projectSlackAppToken}`)
632
- : props.trimEnd() + `\nSLACK_APP_TOKEN=${projectSlackAppToken}\n`;
633
- }
642
+ props = /^#?\s*PRIVATE_SLACK\s*=/m.test(props)
643
+ ? props.replace(/^#?\s*PRIVATE_SLACK\s*=.*/m, 'PRIVATE_SLACK=true')
644
+ : props.trimEnd() + '\nPRIVATE_SLACK=true\n';
634
645
  fs.writeFileSync(projProps, props);
635
- ok('Project-level Slack tokens saved to config/sentinel.properties');
646
+ ok('PRIVATE_SLACK=true set in config/sentinel.properties');
636
647
  }
637
648
  }
638
649
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.4.81",
3
+ "version": "1.4.82",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -151,6 +151,17 @@ class ConfigLoader:
151
151
  project_d = _parse_properties(str(path))
152
152
  d.update({k: v for k, v in project_d.items() if v})
153
153
 
154
+ # If PRIVATE_SLACK=true, load Slack tokens from <projectDir>/slack.properties
155
+ # (gitignored — tokens never live in the config repo).
156
+ if d.get("PRIVATE_SLACK", "").lower() == "true":
157
+ slack_props = self.config_dir.parent / "slack.properties"
158
+ if slack_props.exists():
159
+ slack_d = _parse_properties(str(slack_props))
160
+ d.update({k: v for k, v in slack_d.items() if v})
161
+ logger.debug("Loaded private Slack config from %s", slack_props)
162
+ else:
163
+ logger.warning("PRIVATE_SLACK=true but %s not found — run `sentinel add` to create it", slack_props)
164
+
154
165
  c = SentinelConfig()
155
166
  c.poll_interval_seconds = int(d.get("POLL_INTERVAL_SECONDS", 120))
156
167
  c.smtp_host = d.get("SMTP_HOST", "")
@@ -42,33 +42,12 @@ WORKSPACE_DIR=./workspace
42
42
  # this key instead of the shared Claude Pro subscription.
43
43
  # ANTHROPIC_API_KEY=sk-ant-...
44
44
 
45
- # Slack Bot (optional) Sentinel Boss conversational interface
46
- # Create a Slack App at api.slack.com, enable Socket Mode, add scopes:
47
- # app_mentions:read, chat:write, im:history, channels:history, users:read, reactions:write
48
- # Then install to workspace and paste both tokens here.
49
- # SLACK_BOT_TOKEN=xoxb-...
50
- # SLACK_APP_TOKEN=xapp-...
51
- # Restrict Sentinel Boss to one channel (optional — omit to allow all channels + DMs)
52
- # Use the channel name (e.g. devops-sentinel) or the Slack channel ID (e.g. C01AB2CD3EF)
53
- # Note: requires conversations:read scope on the Slack App if using channel name
54
- # SLACK_CHANNEL=devops-sentinel
55
-
56
- # DM the submitter directly when a fix is applied or blocked (default: true).
57
- # Set to false to only mention them in the channel, without a private DM.
58
- # SLACK_DM_SUBMITTER=true
59
-
60
- # Allowlist of Slack user IDs permitted to give Sentinel Boss commands (RECOMMENDED).
61
- # If set, all other users are silently ignored — even in the configured channel.
62
- # Find a user ID in Slack: click their profile → ⋯ More → Copy member ID (starts with U).
63
- # Comma-separated. Leave unset to allow anyone who can reach the bot (less secure).
64
- # SLACK_ALLOWED_USERS=U01AB2CD3EF, U09GH8IJ7KL
65
-
66
- # Passive bot watcher — seed the watch list on startup with known bot IDs.
67
- # Sentinel will passively queue every message from these bots as issues (no @mention needed).
68
- # You can also add bots at runtime: "@Sentinel listen to @alertbot for project 1881"
69
- # Use "@Sentinel list watched bots" to see the current list.
70
- # Comma-separated list of Slack bot IDs (starts with B, not U).
71
- # SLACK_WATCH_BOT_IDS=B12345678, B87654321
45
+ # Private Slack set to true if this project uses a different Slack workspace
46
+ # than the shared one configured in the workspace sentinel.properties.
47
+ # When true, Sentinel loads Slack tokens from slack.properties in this project
48
+ # directory (gitignored tokens never committed to the config repo).
49
+ # Run `sentinel add` to generate slack.properties interactively.
50
+ # PRIVATE_SLACK=false
72
51
 
73
52
  # Boss mode override — overrides the workspace-level BOSS_MODE for this project only.
74
53
  # Options: standard (default) | strict | fun