@misterhuydo/sentinel 1.5.16 → 1.5.17

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/.cairn/.hint-lock CHANGED
@@ -1 +1 @@
1
- 2026-04-08T14:32:32.252Z
1
+ 2026-04-08T15:32:44.554Z
@@ -1,6 +1,6 @@
1
1
  {
2
- "message": "Auto-checkpoint at 2026-04-08T14:30:49.032Z",
3
- "checkpoint_at": "2026-04-08T14:30:49.109Z",
2
+ "message": "Auto-checkpoint at 2026-04-08T15:37:20.160Z",
3
+ "checkpoint_at": "2026-04-08T15:37:20.240Z",
4
4
  "active_files": [
5
5
  "J:\\Projects\\Sentinel\\cli\\bin\\sentinel.js",
6
6
  "J:\\Projects\\Sentinel\\cli\\lib\\test.js",
@@ -20,7 +20,12 @@
20
20
  "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 29 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n 9 files changed, 313 insertions(+), 66 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
21
21
  "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 30 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n 9 files changed, 314 insertions(+), 66 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
22
22
  "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 31 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n 9 files changed, 315 insertions(+), 66 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
23
- "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 32 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n 9 files changed, 316 insertions(+), 66 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py"
23
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 32 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n 9 files changed, 316 insertions(+), 66 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
24
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 33 ++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n cli/package.json | 2 +-\n sentinel/config_loader.py | 1 +\n 11 files changed, 319 insertions(+), 67 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n M package.json\n M ../sentinel/config_loader.py\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
25
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 34 +++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n cli/package.json | 2 +-\n sentinel/config_loader.py | 1 +\n 11 files changed, 320 insertions(+), 67 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n M package.json\n M ../sentinel/config_loader.py\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
26
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 35 +++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n cli/package.json | 2 +-\n sentinel/config_loader.py | 1 +\n 11 files changed, 321 insertions(+), 67 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n M package.json\n M ../sentinel/config_loader.py\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
27
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 36 +++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n cli/package.json | 2 +-\n sentinel/config_loader.py | 1 +\n 11 files changed, 322 insertions(+), 67 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n M package.json\n M ../sentinel/config_loader.py\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py",
28
+ "[2026-04-08] git-snapshot: .cairn/session.json | 29 ++++-\n .claude/settings.local.json | 47 ++++++-\n cli/.cairn/.hint-lock | 2 +-\n cli/.cairn/minify-map.json | 8 +-\n cli/.cairn/session.json | 37 +++++-\n cli/.cairn/views/62a614_bundle.js | 6 +-\n cli/lib/.cairn/minify-map.json | 6 +\n cli/lib/.cairn/views/fb78ac_upgrade.js | 37 +++++-\n cli/lib/.cairn/views/fc4a1a_add.js | 215 +++++++++++++++++++++++++--------\n cli/package.json | 2 +-\n sentinel/config_loader.py | 1 +\n 11 files changed, 323 insertions(+), 67 deletions(-) | status: M ../.cairn/session.json\n M ../.claude/settings.local.json\n M .cairn/.hint-lock\n M .cairn/minify-map.json\n M .cairn/session.json\n M .cairn/views/62a614_bundle.js\n M lib/.cairn/minify-map.json\n M lib/.cairn/views/fb78ac_upgrade.js\n M lib/.cairn/views/fc4a1a_add.js\n M package.json\n M ../sentinel/config_loader.py\n?? ../.cairn/.cairn-project\n?? ../.cairn/memory/\n?? ../.cairn/minify-map.json\n?? ../.cairn/views/\n?? .cairn/views/23edf4_sentinel_boss.py\n?? .cairn/views/7802b9_cicd_trigger.py\n?? .cairn/views/ac3df4_repo_task_engine.py\n?? lib/.cairn/views/2a85cc_init.js\n?? lib/.cairn/views/e26996_slack-setup.js\n?? ../scripts/fix_ask_codebase_context.py\n?? ../scripts/fix_ask_codebase_stdin.py\n?? ../scripts/fix_chain_slack.py\n?? ../scripts/fix_fstring.py\n?? ../scripts/fix_knowledge_cache.py\n?? ../scripts/fix_knowledge_cache_staleness.py\n?? ../scripts/fix_merge_confirm.py\n?? ../scripts/fix_permission_messages.py\n?? ../scripts/fix_pr_check_head_detect.py\n?? ../scripts/fix_pr_msg_newlines.py\n?? ../scripts/fix_pr_tracking_boss.py\n?? ../scripts/fix_pr_tracking_db.py\n?? ../scripts/fix_pr_tracking_main.py\n?? ../scripts/fix_project_isolation.py\n?? ../scripts/fix_system_prompt.py\n?? ../scripts/fix_two_bugs.py\n?? ../scripts/patch_chain_release.py"
24
29
  ],
25
30
  "mtime_snapshot": {
26
31
  "J:\\Projects\\Sentinel\\cli\\bin\\sentinel.js": 1774252515044.4768,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@misterhuydo/sentinel",
3
- "version": "1.5.16",
3
+ "version": "1.5.17",
4
4
  "description": "Sentinel — Autonomous DevOps Agent installer and manager",
5
5
  "bin": {
6
6
  "sentinel": "./bin/sentinel.js"
@@ -1 +1 @@
1
- __version__ = "1.5.16"
1
+ __version__ = "1.5.17"
@@ -81,7 +81,8 @@ class SentinelConfig:
81
81
  sentinel_dev_repo_path: str = "" # path to Sentinel source repo for Dev Claude
82
82
  sentinel_dev_soak_minutes: int = 30 # minutes to monitor after a Patch restart before publishing
83
83
  sentinel_dev_auto_publish: bool = False # if True, auto-publish to npm after clean soak
84
- auto_publish: bool = False # project-level default; repos inherit this if AUTO_PUBLISH not set in their config
84
+ auto_commit: bool = False # project-level default: push directly to main (no PR); repos can override
85
+ auto_release: bool = False # project-level default: trigger CI/CD pipeline after push; repos can override
85
86
 
86
87
 
87
88
  @dataclass
@@ -110,7 +111,8 @@ class RepoConfig:
110
111
  repo_url: str = ""
111
112
  local_path: str = ""
112
113
  branch: str = "main"
113
- auto_publish: bool | None = None # None = inherit from SentinelConfig.auto_publish; explicit True/False overrides
114
+ auto_commit: bool | None = None # None = inherit from SentinelConfig.auto_commit; explicit True/False overrides
115
+ auto_release: bool | None = None # None = inherit from SentinelConfig.auto_release; explicit True/False overrides
114
116
  cicd_type: str = ""
115
117
  cicd_job_url: str = ""
116
118
  cicd_user: str = "" # Jenkins username for Basic auth (defaults to "sentinel")
@@ -239,8 +241,10 @@ class ConfigLoader:
239
241
  c.sentinel_dev_repo_path = d.get("SENTINEL_DEV_REPO_PATH", "")
240
242
  c.sentinel_dev_soak_minutes = int(d.get("SENTINEL_DEV_SOAK_MINUTES", 30))
241
243
  c.sentinel_dev_auto_publish = d.get("SENTINEL_DEV_AUTO_PUBLISH", "false").lower() == "true"
242
- if "AUTO_PUBLISH" in d:
243
- c.auto_publish = d["AUTO_PUBLISH"].lower() == "true"
244
+ if "AUTO_COMMIT" in d:
245
+ c.auto_commit = d["AUTO_COMMIT"].lower() == "true"
246
+ if "AUTO_RELEASE" in d:
247
+ c.auto_release = d["AUTO_RELEASE"].lower() == "true"
244
248
  self.sentinel = c
245
249
 
246
250
  def _load_log_sources(self):
@@ -290,7 +294,8 @@ class ConfigLoader:
290
294
  r.repo_url = d.get("REPO_URL", "")
291
295
  r.local_path = str(Path(self.config_dir).parent / "repos" / r.repo_name)
292
296
  r.branch = d.get("BRANCH", "main")
293
- r.auto_publish = bool(d["AUTO_PUBLISH"].lower() == "true") if "AUTO_PUBLISH" in d else None
297
+ r.auto_commit = bool(d["AUTO_COMMIT"].lower() == "true") if "AUTO_COMMIT" in d else None
298
+ r.auto_release = bool(d["AUTO_RELEASE"].lower() == "true") if "AUTO_RELEASE" in d else None
294
299
  r.cicd_type = d.get("CICD_TYPE", "")
295
300
  r.cicd_job_url = d.get("CICD_JOB_URL", "")
296
301
  r.cicd_user = d.get("CICD_USER", "")
@@ -318,15 +323,25 @@ class ConfigLoader:
318
323
  self.load()
319
324
 
320
325
 
321
- def resolve_auto_publish(repo: "RepoConfig", sentinel: "SentinelConfig") -> bool:
326
+ def resolve_auto_commit(repo: "RepoConfig", sentinel: "SentinelConfig") -> bool:
322
327
  """
323
- Three-level AUTO_PUBLISH resolution:
324
- 1. Repo-level explicit value (if AUTO_PUBLISH is set in the repo .properties file)
325
- 2. Project-level default (AUTO_PUBLISH in sentinel.properties)
328
+ Three-level AUTO_COMMIT resolution:
329
+ 1. Repo-level explicit value (if AUTO_COMMIT is set in the repo .properties file)
330
+ 2. Project-level default (AUTO_COMMIT in sentinel.properties)
326
331
  3. System default: False
332
+ """
333
+ if repo.auto_commit is not None:
334
+ return repo.auto_commit
335
+ return sentinel.auto_commit
336
+
327
337
 
328
- None on repo.auto_publish means "not explicitly set inherit from project".
338
+ def resolve_auto_release(repo: "RepoConfig", sentinel: "SentinelConfig") -> bool:
339
+ """
340
+ Three-level AUTO_RELEASE resolution:
341
+ 1. Repo-level explicit value (if AUTO_RELEASE is set in the repo .properties file)
342
+ 2. Project-level default (AUTO_RELEASE in sentinel.properties)
343
+ 3. System default: False
329
344
  """
330
- if repo.auto_publish is not None:
331
- return repo.auto_publish
332
- return sentinel.auto_publish
345
+ if repo.auto_release is not None:
346
+ return repo.auto_release
347
+ return sentinel.auto_release
@@ -275,8 +275,8 @@ def plan_cascade(
275
275
  {
276
276
  "repo": r.repo_name,
277
277
  "current_version": v,
278
- "auto_publish": bool(r.auto_publish),
279
- "action": "push to main" if r.auto_publish else "open PR (AUTO_PUBLISH not set inherits project default)",
278
+ "auto_commit": r.auto_commit,
279
+ "action": "push to main" if r.auto_commit is True else ("open PR" if r.auto_commit is False else "inherits project AUTO_COMMIT"),
280
280
  }
281
281
  for r, v in all_dependents
282
282
  ],
@@ -1,7 +1,7 @@
1
1
  """
2
2
  git_manager.py — Git operations and GitHub PR creation.
3
3
 
4
- Supports two modes (driven by repo.auto_publish):
4
+ Supports two modes (driven by repo.auto_commit):
5
5
  True → apply fix directly to main branch and push
6
6
  False → push to sentinel/fix-<fp> branch and open a GitHub PR
7
7
  """
@@ -15,7 +15,7 @@ from pathlib import Path
15
15
 
16
16
  import requests
17
17
 
18
- from .config_loader import RepoConfig, SentinelConfig, resolve_auto_publish
18
+ from .config_loader import RepoConfig, SentinelConfig, resolve_auto_commit
19
19
  from .log_parser import ErrorEvent
20
20
 
21
21
  logger = logging.getLogger(__name__)
@@ -251,16 +251,16 @@ def push_dep_update(
251
251
  commit_hash: str,
252
252
  ) -> tuple[str, str, bool]:
253
253
  """
254
- Push a dependency update commit. AUTO_PUBLISH=true → main branch.
255
- AUTO_PUBLISH=false → sentinel/dep-<artifact>-<version> branch + open PR.
254
+ Push a dependency update commit. AUTO_COMMIT=true → main branch.
255
+ AUTO_COMMIT=false → sentinel/dep-<artifact>-<version> branch + open PR.
256
256
  Returns (branch, pr_url, push_ok).
257
257
  push_ok=False means the commit is local only (no write access) — chain release continues.
258
258
  """
259
259
  env = _git_env(repo)
260
260
  local_path = repo.local_path
261
- auto_publish = resolve_auto_publish(repo, cfg)
261
+ auto_commit = resolve_auto_commit(repo, cfg)
262
262
 
263
- if auto_publish:
263
+ if auto_commit:
264
264
  r = _git(["push", "origin", repo.branch], cwd=local_path, env=env)
265
265
  if r.returncode != 0:
266
266
  logger.warning(
@@ -348,16 +348,16 @@ def publish(
348
348
  commit_hash: str,
349
349
  ) -> tuple[str, str]:
350
350
  """
351
- Push the fix and (if AUTO_PUBLISH=false) open a PR.
351
+ Push the fix and (if AUTO_COMMIT=false) open a PR.
352
352
 
353
353
  Returns:
354
- (branch, pr_url) — pr_url is "" when AUTO_PUBLISH=true
354
+ (branch, pr_url) — pr_url is "" when AUTO_COMMIT=true
355
355
  """
356
356
  env = _git_env(repo)
357
357
  local_path = repo.local_path
358
- auto_publish = resolve_auto_publish(repo, cfg)
358
+ auto_commit = resolve_auto_commit(repo, cfg)
359
359
 
360
- if not auto_publish:
360
+ if not auto_commit:
361
361
  if remote_fix_exists(repo, event.fingerprint, cfg):
362
362
  logger.info(
363
363
  "Remote fix branch already exists for %s — skipping duplicate push",
@@ -365,7 +365,7 @@ def publish(
365
365
  )
366
366
  return "", ""
367
367
 
368
- if auto_publish:
368
+ if auto_commit:
369
369
  r = _git(["push", "origin", repo.branch], cwd=local_path, env=env)
370
370
  if r.returncode != 0:
371
371
  logger.error("git push failed:\n%s", r.stderr)
@@ -21,7 +21,7 @@ from datetime import datetime, timezone
21
21
  from pathlib import Path
22
22
 
23
23
  from .cairn_client import ensure_installed as cairn_installed, index_repo
24
- from .config_loader import ConfigLoader, SentinelConfig, resolve_auto_publish
24
+ from .config_loader import ConfigLoader, SentinelConfig, resolve_auto_commit, resolve_auto_release
25
25
  from .fix_engine import generate_fix
26
26
  from .git_manager import apply_and_commit, publish, _git_env, MissingToolError, MavenAuthError, poll_open_prs
27
27
  from .cicd_trigger import trigger as cicd_trigger
@@ -183,7 +183,8 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
183
183
  if not repo:
184
184
  return
185
185
 
186
- auto_publish = resolve_auto_publish(repo, sentinel)
186
+ auto_commit = resolve_auto_commit(repo, sentinel)
187
+ auto_release = resolve_auto_release(repo, sentinel)
187
188
 
188
189
  # ── Dismissed errors — skip silently (human explicitly said so) ───────────
189
190
  if store.is_dismissed(event.fingerprint):
@@ -195,8 +196,8 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
195
196
  return
196
197
 
197
198
  # ── Determine what we can do before alerting ──────────────────────────────
198
- cannot_fix = event.is_infra_issue or (event.severity == "CRITICAL" and auto_publish)
199
- fix_status = "cannot_fix" if cannot_fix else ("will_fix_pr" if not auto_publish else "attempting")
199
+ cannot_fix = event.is_infra_issue or (event.severity == "CRITICAL" and auto_commit)
200
+ fix_status = "cannot_fix" if cannot_fix else ("will_fix_pr" if not auto_commit else "attempting")
200
201
 
201
202
  stack_lines = getattr(event, "stack_trace", None)
202
203
  stack_preview = ""
@@ -229,8 +230,8 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
229
230
  store.record_fix(event.fingerprint, "skipped", repo_name=repo.repo_name)
230
231
  return
231
232
 
232
- if event.severity == "CRITICAL" and auto_publish:
233
- logger.warning("CRITICAL in auto-publish repo '%s' — alerted, human review needed", repo.repo_name)
233
+ if event.severity == "CRITICAL" and auto_commit:
234
+ logger.warning("CRITICAL in auto-commit repo '%s' — alerted, human review needed", repo.repo_name)
234
235
  store.record_fix(event.fingerprint, "skipped", repo_name=repo.repo_name)
235
236
  return
236
237
 
@@ -305,7 +306,7 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
305
306
  branch, pr_url = publish(event, repo, sentinel, commit_hash)
306
307
  store.record_fix(
307
308
  event.fingerprint,
308
- "applied" if auto_publish else "pending",
309
+ "applied" if auto_commit else "pending",
309
310
  patch_path=str(patch_path),
310
311
  commit_hash=commit_hash,
311
312
  branch=branch,
@@ -318,6 +319,10 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
318
319
  _progress(f":white_check_mark: Fix committed — PR opened: {pr_url}")
319
320
  else:
320
321
  _progress(f":white_check_mark: Fix pushed to `{branch}` (`{commit_hash[:8]}`)")
322
+ if auto_commit and not auto_release:
323
+ store.add_pending_release(repo.repo_name, commit_hash, branch,
324
+ description=event.message[:120],
325
+ fingerprint=event.fingerprint)
321
326
 
322
327
  send_fix_notification(sentinel, {
323
328
  "source": event.source,
@@ -330,11 +335,11 @@ async def _handle_error(event: ErrorEvent, cfg_loader: ConfigLoader, store: Stat
330
335
  "commit_hash": commit_hash,
331
336
  "branch": branch,
332
337
  "pr_url": pr_url,
333
- "auto_publish": auto_publish,
338
+ "auto_commit": auto_commit,
334
339
  "files_changed": [],
335
340
  })
336
341
 
337
- if auto_publish:
342
+ if auto_commit and auto_release:
338
343
  ok = cicd_trigger(repo, store, event.fingerprint)
339
344
  if ok and repo.cicd_type.lower() in ("jenkins_release", "jenkins-release"):
340
345
  _run_cascade(repo, sentinel, cfg_loader)
@@ -375,7 +380,8 @@ async def _handle_issue(event: IssueEvent, cfg_loader: ConfigLoader, store: Stat
375
380
  )
376
381
  return # Leave the file so admin can add the header
377
382
 
378
- auto_publish = resolve_auto_publish(repo, sentinel)
383
+ auto_commit = resolve_auto_commit(repo, sentinel)
384
+ auto_release = resolve_auto_release(repo, sentinel)
379
385
 
380
386
  # Post "working on" to channel and capture thread_ts for progress replies
381
387
  from .notify import slack_alert as _slack_alert, slack_thread_reply as _slack_reply
@@ -438,7 +444,7 @@ async def _handle_issue(event: IssueEvent, cfg_loader: ConfigLoader, store: Stat
438
444
  branch, pr_url = publish(event, repo, sentinel, commit_hash)
439
445
  store.record_fix(
440
446
  event.fingerprint,
441
- "applied" if auto_publish else "pending",
447
+ "applied" if auto_commit else "pending",
442
448
  patch_path=str(patch_path),
443
449
  commit_hash=commit_hash,
444
450
  branch=branch,
@@ -457,17 +463,22 @@ async def _handle_issue(event: IssueEvent, cfg_loader: ConfigLoader, store: Stat
457
463
  "commit_hash": commit_hash,
458
464
  "branch": branch,
459
465
  "pr_url": pr_url,
460
- "auto_publish": auto_publish,
466
+ "auto_commit": auto_commit,
461
467
  "files_changed": [],
462
468
  })
463
469
  if pr_url:
464
470
  _progress(f":arrow_right: <{pr_url}|PR opened> — awaiting review")
471
+ else:
472
+ if auto_commit and not auto_release:
473
+ store.add_pending_release(repo.repo_name, commit_hash, branch,
474
+ description=event.message[:120],
475
+ fingerprint=event.fingerprint)
465
476
  notify_fix_applied(sentinel, event.source, event.message,
466
477
  repo_name=repo.repo_name, branch=branch, pr_url=pr_url,
467
478
  submitter_user_id=submitter_uid, origin_channel=_origin_channel)
468
479
  mark_done(event.issue_file)
469
480
 
470
- if auto_publish:
481
+ if auto_commit and auto_release:
471
482
  ok = cicd_trigger(repo, store, event.fingerprint)
472
483
  if ok:
473
484
  _progress(f":rocket: Release triggered via {repo.cicd_type}")
@@ -529,7 +540,7 @@ async def _handle_issue(event: IssueEvent, cfg_loader: ConfigLoader, store: Stat
529
540
  branch, pr_url = publish(event, repo, sentinel, commit_hash)
530
541
  store.record_fix(
531
542
  event.fingerprint,
532
- "applied" if auto_publish else "pending",
543
+ "applied" if auto_commit else "pending",
533
544
  patch_path=str(patch_path), commit_hash=commit_hash,
534
545
  branch=branch, pr_url=pr_url, repo_name=repo.repo_name, sentinel_marker=marker,
535
546
  )
@@ -539,15 +550,20 @@ async def _handle_issue(event: IssueEvent, cfg_loader: ConfigLoader, store: Stat
539
550
  "message": event.message, "stack_trace": event.body,
540
551
  "repo_name": repo.repo_name, "commit_hash": commit_hash,
541
552
  "branch": branch, "pr_url": pr_url,
542
- "auto_publish": auto_publish, "files_changed": [],
553
+ "auto_commit": auto_commit, "files_changed": [],
543
554
  })
544
555
  if pr_url:
545
556
  _progress(f":arrow_right: <{pr_url}|PR opened> — awaiting review")
557
+ else:
558
+ if auto_commit and not auto_release:
559
+ store.add_pending_release(repo.repo_name, commit_hash, branch,
560
+ description=event.message[:120],
561
+ fingerprint=event.fingerprint)
546
562
  notify_fix_applied(sentinel, event.source, event.message,
547
563
  repo_name=repo.repo_name, branch=branch, pr_url=pr_url,
548
564
  submitter_user_id=submitter_uid, origin_channel=_origin_channel)
549
565
  mark_done(event.issue_file)
550
- if auto_publish:
566
+ if auto_commit and auto_release:
551
567
  ok = cicd_trigger(repo, store, event.fingerprint)
552
568
  if ok:
553
569
  _progress(f":rocket: Release triggered via {repo.cicd_type}")
@@ -28,7 +28,7 @@ from dataclasses import dataclass, field
28
28
  from datetime import datetime, timezone
29
29
  from pathlib import Path
30
30
 
31
- from .config_loader import RepoConfig, SentinelConfig, resolve_auto_publish
31
+ from .config_loader import RepoConfig, SentinelConfig, resolve_auto_commit, resolve_auto_release
32
32
  from .fix_engine import _claude_cmd, _run_claude_attempt, _is_auth_error, _progress_from_line
33
33
  from .git_manager import _git_env
34
34
 
@@ -276,12 +276,13 @@ def run_repo_task(
276
276
  return "skip", "Claude completed but made no changes to the codebase."
277
277
 
278
278
  commit_hash = after_hash
279
- auto_publish = resolve_auto_publish(repo, cfg)
279
+ auto_commit = resolve_auto_commit(repo, cfg)
280
+ auto_release = resolve_auto_release(repo, cfg)
280
281
 
281
282
  if on_progress:
282
283
  on_progress(f":arrow_up: Pushing to `{repo.repo_name}`...")
283
284
 
284
- if auto_publish:
285
+ if auto_commit:
285
286
  r = subprocess.run(
286
287
  ["git", "push", "origin", repo.branch],
287
288
  cwd=local_path, capture_output=True, text=True, env=env, timeout=60,
@@ -290,7 +291,16 @@ def run_repo_task(
290
291
  logger.error("git push failed for %s: %s", repo.repo_name, r.stderr[:300])
291
292
  return "error", f"git push failed: {r.stderr.strip()[:200]}"
292
293
  logger.info("Repo task: pushed to %s/%s sha=%s", repo.repo_name, repo.branch, commit_hash[:8])
293
- if repo.cicd_type:
294
+ if store and not auto_release:
295
+ try:
296
+ store.add_pending_release(
297
+ repo.repo_name, commit_hash, repo.branch,
298
+ description=getattr(task, "description", "")[:120],
299
+ fingerprint=task.fingerprint,
300
+ )
301
+ except Exception as exc:
302
+ logger.debug("Could not record pending release: %s", exc)
303
+ if repo.cicd_type and auto_release:
294
304
  try:
295
305
  from .cicd_trigger import trigger as cicd_trigger
296
306
  ok = cicd_trigger(repo, None, task.fingerprint)
@@ -40,7 +40,7 @@ _SYSTEM = """\
40
40
  You are Sentinel Boss — the AI interface for Sentinel, a 24/7 autonomous DevOps agent.
41
41
 
42
42
  Sentinel watches production logs, detects errors, generates code fixes via Claude Code,
43
- and opens GitHub PRs for admin review (or pushes directly if AUTO_PUBLISH=true).
43
+ and opens GitHub PRs for admin review (or pushes directly if AUTO_COMMIT=true).
44
44
 
45
45
  Your job:
46
46
  - Understand what the DevOps engineer needs in natural language
@@ -372,7 +372,7 @@ Common usage questions and answers:
372
372
  Q: How do I ask you to fix a bug?
373
373
  A: Just describe it in plain language: "fix the NullPointerException in OrderService".
374
374
  Sentinel will classify the error, find the right repo, and open a PR (or push directly
375
- if AUTO_PUBLISH=true).
375
+ if AUTO_COMMIT=true).
376
376
 
377
377
  Q: How do I review and merge a fix PR?
378
378
  A: Say "list pending PRs" to see open Sentinel fix PRs. Then "merge the fix for TypeLib"
@@ -412,9 +412,11 @@ A: After every fix, Sentinel injects a SENTINEL:#<fingerprint> marker into each
412
412
  method. When that marker appears in production logs, a quiet period starts. After
413
413
  MARKER_CONFIRM_HOURS with no recurrence of the original error, the fix is confirmed.
414
414
 
415
- Q: What is AUTO_PUBLISH?
416
- A: false (default): Sentinel opens a GitHub PR for admin review; merge it when satisfied.
417
- true: Sentinel pushes directly to main and triggers CI/CD.
415
+ Q: What are AUTO_COMMIT and AUTO_RELEASE?
416
+ A: AUTO_COMMIT=false (default): Sentinel opens a GitHub PR for admin review; merge it when satisfied.
417
+ AUTO_COMMIT=true: Sentinel pushes directly to main automatically.
418
+ AUTO_RELEASE=false (default): no CI/CD pipeline triggered; admin releases manually.
419
+ AUTO_RELEASE=true: Sentinel triggers Jenkins/GHA after each push to main.
418
420
 
419
421
  Q: How do I pause Sentinel without stopping the process?
420
422
  A: "pause sentinel" — creates a SENTINEL_PAUSE file. All auto-fix activity stops
@@ -445,8 +447,8 @@ SENTINEL ARCHITECTURE
445
447
  - Fix engine: Claude Code headless (claude --print) with structured prompt (error + stack trace
446
448
  + Cairn MCP context); unified diff output; max 5 files / 200 lines
447
449
  - Commit: git pull --rebase, apply patch, run tests, commit with sentinel/fix-<fp> marker
448
- - Publish: AUTO_PUBLISH=true → push to main + CI/CD trigger;
449
- AUTO_PUBLISH=falsebranch + GitHub PR
450
+ - Publish: AUTO_COMMIT=true → push to main; AUTO_COMMIT=false → branch + GitHub PR
451
+ AUTO_RELEASE=trueCI/CD trigger after push; AUTO_RELEASE=false → manual release
450
452
  - Fix confirmation: SENTINEL marker injected into modified methods; marker appearing in
451
453
  production logs starts quiet period; after MARKER_CONFIRM_HOURS with no recurrence → confirmed
452
454
 
@@ -474,7 +476,8 @@ Release management:
474
476
  Key config options:
475
477
  - ANTHROPIC_API_KEY: Boss conversation (structured tool-use); optional if CLAUDE_PRO_FOR_TASKS=true
476
478
  - CLAUDE_PRO_FOR_TASKS=true (default): Fix Engine uses claude CLI (Claude Pro OAuth billing)
477
- - AUTO_PUBLISH=false (default): Sentinel opens PRs; =true: pushes directly to main
479
+ - AUTO_COMMIT=false (default): Sentinel opens PRs; =true: pushes directly to main
480
+ - AUTO_RELEASE=false (default): no CI/CD trigger; =true: triggers Jenkins/GHA after push
478
481
  - SYNC_RETENTION_DAYS (default 30): delete synced logs older than N days
479
482
  - SYNC_MAX_FILE_MB (default 200): truncate synced logs exceeding this size
480
483
  - HEALTH_URL: HTTP endpoint per repo; JSON with "Status": "true" = healthy
@@ -713,9 +716,11 @@ _TOOLS = [
713
716
  "name": "get_status",
714
717
  "description": (
715
718
  "Get recent errors, fixes applied, fixes pending review, open PRs, "
719
+ "pending releases (commits pushed to main but not yet released — AUTO_RELEASE=false), "
716
720
  "and the live task queue (issues and repo tasks waiting to be picked up). "
717
721
  "Use for: 'what happened today?', 'any issues?', 'how are things?', "
718
722
  "'what are the open PRs?', 'did sentinel fix anything?', "
723
+ "'what needs to be released?', 'which repos have unreleased commits?', "
719
724
  "'what is queued?', 'what is pending?', 'progress on X?'"
720
725
  ),
721
726
  "input_schema": {
@@ -873,7 +878,7 @@ _TOOLS = [
873
878
  "description": (
874
879
  "ADMIN ONLY. Submit a feature, fix, refactor, or scheduled deploy task for a managed repo. "
875
880
  "Claude Code will run against the repo's local clone, implement the change, "
876
- "commit, and push (or open a PR if AUTO_PUBLISH=false). "
881
+ "commit, and push (or open a PR if AUTO_COMMIT=false). "
877
882
  "ALWAYS gather a complete spec first — ask follow-up questions until unambiguous. "
878
883
  "Use for: 'add X to elprint-connector-service', 'fix Y in cairn', "
879
884
  "'refactor OrderService', 'deploy UIB at 3 AM tomorrow', "
@@ -1517,7 +1522,7 @@ _TOOLS = [
1517
1522
  "ADMIN ONLY. Merge a branch or PR into the main branch. "
1518
1523
  "ALWAYS call with confirmed=false first to show details for admin review — "
1519
1524
  "never merge without showing the plan first. "
1520
- "Use for Sentinel fix PRs (AUTO_PUBLISH=false), Renovate/external PRs by number, "
1525
+ "Use for Sentinel fix PRs (AUTO_COMMIT=false), Renovate/external PRs by number, "
1521
1526
  "or any arbitrary branch by name (branch_name). "
1522
1527
  "confirmed=false fetches and shows details; confirmed=true executes the merge. "
1523
1528
  "e.g. 'merge the fix for Whydah-TypeLib', 'merge TypeLib PR #247', "
@@ -1618,7 +1623,7 @@ _TOOLS = [
1618
1623
  "enum": ["build", "release", "update_deps", "release_and_cascade"],
1619
1624
  "description": (
1620
1625
  "build: trigger Jenkins build only. "
1621
- "release: trigger Maven Release; auto-cascades if AUTO_PUBLISH=true. "
1626
+ "release: trigger Maven Release; auto-cascades if AUTO_COMMIT=true. "
1622
1627
  "update_deps: update dependency version in target repos — source is ALREADY released, do NOT trigger a new release. "
1623
1628
  "Use this when the user says 'update X to version Y' or 'bump X dep to Y in repo Z'. "
1624
1629
  "release_and_cascade: release source_repo then cascade to all dependents."
@@ -2029,6 +2034,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
2029
2034
  "queued_issues": queued_issues,
2030
2035
  "queued_repo_tasks": pending_repo_tasks,
2031
2036
  "scheduled_tasks": scheduled_tasks,
2037
+ "pending_releases": store.get_pending_releases(),
2032
2038
  })
2033
2039
 
2034
2040
  if name == "check_auth_status":
@@ -4312,7 +4318,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
4312
4318
  "job_url": repo.cicd_job_url,
4313
4319
  "cascade": cascade_plan["dependents"],
4314
4320
  "cascade_note": cascade_note,
4315
- "auto_publish_source": repo.auto_publish,
4321
+ "auto_commit_source": repo.auto_commit,
4316
4322
  "confirm_prompt": "Reply with confirmed=true to proceed.",
4317
4323
  })
4318
4324
 
@@ -4345,9 +4351,11 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
4345
4351
  logger.info("Boss manage_release: release triggered for %s by %s (success=%s)", source_repo, user_id, success)
4346
4352
  if not success:
4347
4353
  return json.dumps({"status": "failed", "repo": source_repo, "error": "Jenkins release trigger failed — check logs"})
4354
+ store.clear_pending_releases(source_repo)
4348
4355
 
4349
- # Cascade immediately if release_and_cascade, or if AUTO_PUBLISH=true
4350
- do_cascade = (operation == "release_and_cascade") or repo.auto_publish
4356
+ # Cascade immediately if release_and_cascade, or if AUTO_COMMIT=true
4357
+ from .config_loader import resolve_auto_commit as _resolve_auto_commit
4358
+ do_cascade = (operation == "release_and_cascade") or _resolve_auto_commit(repo, cfg_loader.sentinel)
4351
4359
  if do_cascade:
4352
4360
  artifact_id = get_artifact_id(repo.local_path)
4353
4361
  new_version = get_release_version(repo.local_path)
@@ -4365,7 +4373,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
4365
4373
  "version": new_version,
4366
4374
  "cascade": [{"repo": r.repo_name, "success": r.success, "pr_url": r.pr_url, "error": r.error} for r in results],
4367
4375
  })
4368
- return json.dumps({"status": "released", "repo": source_repo, "note": "Cascade will run automatically on next poll if AUTO_PUBLISH=true."})
4376
+ return json.dumps({"status": "released", "repo": source_repo, "note": "Cascade will run automatically on next poll if AUTO_COMMIT=true."})
4369
4377
 
4370
4378
  if operation == "update_deps":
4371
4379
  from .dependency_manager import get_latest_released_version
@@ -4427,10 +4435,11 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
4427
4435
  "artifact_id": artifact_id,
4428
4436
  "release_version": release_ver,
4429
4437
  "cicd_url": repo.cicd_job_url,
4430
- "auto_publish": repo.auto_publish,
4438
+ "auto_commit": repo.auto_commit,
4431
4439
  })
4432
4440
 
4433
4441
  # ── Plan phase ───────────────────────────────────────────────────────
4442
+ from .config_loader import resolve_auto_commit as _resolve_auto_commit
4434
4443
  if not confirmed:
4435
4444
  plan_steps = []
4436
4445
  for i, step in enumerate(steps):
@@ -4448,7 +4457,7 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
4448
4457
  "repo": step["repo"],
4449
4458
  "release_version": step["release_version"],
4450
4459
  "jenkins_url": step["cicd_url"],
4451
- "mode": "push to main" if step["auto_publish"] else "open PR",
4460
+ "mode": "push to main" if step["auto_commit"] else "open PR",
4452
4461
  })
4453
4462
  return json.dumps({
4454
4463
  "plan": f"Sequential release chain: {' → '.join(s['repo'] for s in steps)}",
@@ -77,6 +77,16 @@ class StateStore:
77
77
  dismissed_at TEXT NOT NULL,
78
78
  note TEXT -- optional free-text explanation
79
79
  );
80
+
81
+ CREATE TABLE IF NOT EXISTS pending_releases (
82
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
83
+ repo_name TEXT NOT NULL,
84
+ commit_hash TEXT NOT NULL,
85
+ branch TEXT NOT NULL,
86
+ description TEXT, -- short summary of what was committed
87
+ fingerprint TEXT, -- error/issue fingerprint that triggered it
88
+ committed_at TEXT NOT NULL
89
+ );
80
90
  """)
81
91
  self._migrate()
82
92
  logger.debug("StateStore initialised at %s", self.db_path)
@@ -629,6 +639,33 @@ class StateStore:
629
639
  ).fetchall()
630
640
  return [dict(r) for r in rows]
631
641
 
642
+ # ── Pending releases ──────────────────────────────────────────────────────
643
+
644
+ def add_pending_release(self, repo_name: str, commit_hash: str, branch: str,
645
+ description: str = "", fingerprint: str = "") -> None:
646
+ """Record that a commit was pushed to main but not yet released (AUTO_RELEASE=false)."""
647
+ with self._conn() as conn:
648
+ conn.execute(
649
+ "INSERT INTO pending_releases (repo_name, commit_hash, branch, description, fingerprint, committed_at) "
650
+ "VALUES (?, ?, ?, ?, ?, ?)",
651
+ (repo_name, commit_hash, branch, description, fingerprint, _now()),
652
+ )
653
+
654
+ def clear_pending_releases(self, repo_name: str) -> int:
655
+ """Mark all pending releases for a repo as cleared (after a release is triggered). Returns rows deleted."""
656
+ with self._conn() as conn:
657
+ cur = conn.execute("DELETE FROM pending_releases WHERE repo_name=?", (repo_name,))
658
+ return cur.rowcount
659
+
660
+ def get_pending_releases(self) -> list[dict]:
661
+ """Return all repos with commits pushed but not yet released."""
662
+ with self._conn() as conn:
663
+ rows = conn.execute(
664
+ "SELECT repo_name, commit_hash, branch, description, fingerprint, committed_at "
665
+ "FROM pending_releases ORDER BY committed_at ASC"
666
+ ).fetchall()
667
+ return [dict(r) for r in rows]
668
+
632
669
  # ── Knowledge cache (ask_codebase results) ────────────────────────────────
633
670
 
634
671
  def get_knowledge(self, repo_name: str, question: str) -> "str | None":