@coralai/sps-cli 0.6.0

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 (145) hide show
  1. package/dist/commands/cardAdd.d.ts +2 -0
  2. package/dist/commands/cardAdd.d.ts.map +1 -0
  3. package/dist/commands/cardAdd.js +65 -0
  4. package/dist/commands/cardAdd.js.map +1 -0
  5. package/dist/commands/doctor.d.ts +9 -0
  6. package/dist/commands/doctor.d.ts.map +1 -0
  7. package/dist/commands/doctor.js +264 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/monitorTick.d.ts +2 -0
  10. package/dist/commands/monitorTick.d.ts.map +1 -0
  11. package/dist/commands/monitorTick.js +47 -0
  12. package/dist/commands/monitorTick.js.map +1 -0
  13. package/dist/commands/pipelineTick.d.ts +2 -0
  14. package/dist/commands/pipelineTick.d.ts.map +1 -0
  15. package/dist/commands/pipelineTick.js +44 -0
  16. package/dist/commands/pipelineTick.js.map +1 -0
  17. package/dist/commands/pmCommand.d.ts +2 -0
  18. package/dist/commands/pmCommand.d.ts.map +1 -0
  19. package/dist/commands/pmCommand.js +159 -0
  20. package/dist/commands/pmCommand.js.map +1 -0
  21. package/dist/commands/projectInit.d.ts +2 -0
  22. package/dist/commands/projectInit.d.ts.map +1 -0
  23. package/dist/commands/projectInit.js +75 -0
  24. package/dist/commands/projectInit.js.map +1 -0
  25. package/dist/commands/qaTick.d.ts +2 -0
  26. package/dist/commands/qaTick.d.ts.map +1 -0
  27. package/dist/commands/qaTick.js +43 -0
  28. package/dist/commands/qaTick.js.map +1 -0
  29. package/dist/commands/schedulerTick.d.ts +2 -0
  30. package/dist/commands/schedulerTick.d.ts.map +1 -0
  31. package/dist/commands/schedulerTick.js +45 -0
  32. package/dist/commands/schedulerTick.js.map +1 -0
  33. package/dist/commands/tick.d.ts +14 -0
  34. package/dist/commands/tick.d.ts.map +1 -0
  35. package/dist/commands/tick.js +251 -0
  36. package/dist/commands/tick.js.map +1 -0
  37. package/dist/commands/workerLaunch.d.ts +2 -0
  38. package/dist/commands/workerLaunch.d.ts.map +1 -0
  39. package/dist/commands/workerLaunch.js +56 -0
  40. package/dist/commands/workerLaunch.js.map +1 -0
  41. package/dist/core/config.d.ts +38 -0
  42. package/dist/core/config.d.ts.map +1 -0
  43. package/dist/core/config.js +131 -0
  44. package/dist/core/config.js.map +1 -0
  45. package/dist/core/context.d.ts +23 -0
  46. package/dist/core/context.d.ts.map +1 -0
  47. package/dist/core/context.js +28 -0
  48. package/dist/core/context.js.map +1 -0
  49. package/dist/core/lock.d.ts +14 -0
  50. package/dist/core/lock.d.ts.map +1 -0
  51. package/dist/core/lock.js +65 -0
  52. package/dist/core/lock.js.map +1 -0
  53. package/dist/core/logger.d.ts +24 -0
  54. package/dist/core/logger.d.ts.map +1 -0
  55. package/dist/core/logger.js +62 -0
  56. package/dist/core/logger.js.map +1 -0
  57. package/dist/core/paths.d.ts +27 -0
  58. package/dist/core/paths.d.ts.map +1 -0
  59. package/dist/core/paths.js +29 -0
  60. package/dist/core/paths.js.map +1 -0
  61. package/dist/core/queue.d.ts +14 -0
  62. package/dist/core/queue.d.ts.map +1 -0
  63. package/dist/core/queue.js +38 -0
  64. package/dist/core/queue.js.map +1 -0
  65. package/dist/core/state.d.ts +32 -0
  66. package/dist/core/state.d.ts.map +1 -0
  67. package/dist/core/state.js +52 -0
  68. package/dist/core/state.js.map +1 -0
  69. package/dist/engines/CloseoutEngine.d.ts +60 -0
  70. package/dist/engines/CloseoutEngine.d.ts.map +1 -0
  71. package/dist/engines/CloseoutEngine.js +596 -0
  72. package/dist/engines/CloseoutEngine.js.map +1 -0
  73. package/dist/engines/ExecutionEngine.d.ts +65 -0
  74. package/dist/engines/ExecutionEngine.d.ts.map +1 -0
  75. package/dist/engines/ExecutionEngine.js +603 -0
  76. package/dist/engines/ExecutionEngine.js.map +1 -0
  77. package/dist/engines/MonitorEngine.d.ts +39 -0
  78. package/dist/engines/MonitorEngine.d.ts.map +1 -0
  79. package/dist/engines/MonitorEngine.js +473 -0
  80. package/dist/engines/MonitorEngine.js.map +1 -0
  81. package/dist/engines/SchedulerEngine.d.ts +24 -0
  82. package/dist/engines/SchedulerEngine.d.ts.map +1 -0
  83. package/dist/engines/SchedulerEngine.js +195 -0
  84. package/dist/engines/SchedulerEngine.js.map +1 -0
  85. package/dist/interfaces/HookProvider.d.ts +9 -0
  86. package/dist/interfaces/HookProvider.d.ts.map +1 -0
  87. package/dist/interfaces/HookProvider.js +2 -0
  88. package/dist/interfaces/HookProvider.js.map +1 -0
  89. package/dist/interfaces/Notifier.d.ts +11 -0
  90. package/dist/interfaces/Notifier.d.ts.map +1 -0
  91. package/dist/interfaces/Notifier.js +2 -0
  92. package/dist/interfaces/Notifier.js.map +1 -0
  93. package/dist/interfaces/RepoBackend.d.ts +23 -0
  94. package/dist/interfaces/RepoBackend.d.ts.map +1 -0
  95. package/dist/interfaces/RepoBackend.js +2 -0
  96. package/dist/interfaces/RepoBackend.js.map +1 -0
  97. package/dist/interfaces/TaskBackend.d.ts +24 -0
  98. package/dist/interfaces/TaskBackend.d.ts.map +1 -0
  99. package/dist/interfaces/TaskBackend.js +2 -0
  100. package/dist/interfaces/TaskBackend.js.map +1 -0
  101. package/dist/interfaces/WorkerProvider.d.ts +23 -0
  102. package/dist/interfaces/WorkerProvider.d.ts.map +1 -0
  103. package/dist/interfaces/WorkerProvider.js +2 -0
  104. package/dist/interfaces/WorkerProvider.js.map +1 -0
  105. package/dist/main.d.ts +3 -0
  106. package/dist/main.d.ts.map +1 -0
  107. package/dist/main.js +226 -0
  108. package/dist/main.js.map +1 -0
  109. package/dist/models/types.d.ts +68 -0
  110. package/dist/models/types.d.ts.map +1 -0
  111. package/dist/models/types.js +2 -0
  112. package/dist/models/types.js.map +1 -0
  113. package/dist/providers/ClaudeWorkerProvider.d.ts +84 -0
  114. package/dist/providers/ClaudeWorkerProvider.d.ts.map +1 -0
  115. package/dist/providers/ClaudeWorkerProvider.js +293 -0
  116. package/dist/providers/ClaudeWorkerProvider.js.map +1 -0
  117. package/dist/providers/CodexWorkerProvider.d.ts +50 -0
  118. package/dist/providers/CodexWorkerProvider.d.ts.map +1 -0
  119. package/dist/providers/CodexWorkerProvider.js +275 -0
  120. package/dist/providers/CodexWorkerProvider.js.map +1 -0
  121. package/dist/providers/GitLabRepoBackend.d.ts +42 -0
  122. package/dist/providers/GitLabRepoBackend.d.ts.map +1 -0
  123. package/dist/providers/GitLabRepoBackend.js +280 -0
  124. package/dist/providers/GitLabRepoBackend.js.map +1 -0
  125. package/dist/providers/MarkdownTaskBackend.d.ts +88 -0
  126. package/dist/providers/MarkdownTaskBackend.d.ts.map +1 -0
  127. package/dist/providers/MarkdownTaskBackend.js +414 -0
  128. package/dist/providers/MarkdownTaskBackend.js.map +1 -0
  129. package/dist/providers/MatrixNotifier.d.ts +30 -0
  130. package/dist/providers/MatrixNotifier.d.ts.map +1 -0
  131. package/dist/providers/MatrixNotifier.js +82 -0
  132. package/dist/providers/MatrixNotifier.js.map +1 -0
  133. package/dist/providers/PlaneTaskBackend.d.ts +86 -0
  134. package/dist/providers/PlaneTaskBackend.d.ts.map +1 -0
  135. package/dist/providers/PlaneTaskBackend.js +409 -0
  136. package/dist/providers/PlaneTaskBackend.js.map +1 -0
  137. package/dist/providers/TrelloTaskBackend.d.ts +53 -0
  138. package/dist/providers/TrelloTaskBackend.d.ts.map +1 -0
  139. package/dist/providers/TrelloTaskBackend.js +300 -0
  140. package/dist/providers/TrelloTaskBackend.js.map +1 -0
  141. package/dist/providers/registry.d.ts +10 -0
  142. package/dist/providers/registry.d.ts.map +1 -0
  143. package/dist/providers/registry.js +29 -0
  144. package/dist/providers/registry.js.map +1 -0
  145. package/package.json +36 -0
@@ -0,0 +1,159 @@
1
+ import { ProjectContext } from '../core/context.js';
2
+ import { createTaskBackend } from '../providers/registry.js';
3
+ import { Logger } from '../core/logger.js';
4
+ const VALID_STATES = ['Planning', 'Backlog', 'Todo', 'Inprogress', 'QA', 'Done'];
5
+ export async function executePmCommand(project, subcommand, positionals, flags) {
6
+ const log = new Logger('pm', project);
7
+ const jsonOutput = !!flags.json;
8
+ let ctx;
9
+ try {
10
+ ctx = ProjectContext.load(project);
11
+ }
12
+ catch (err) {
13
+ const msg = err instanceof Error ? err.message : String(err);
14
+ if (jsonOutput) {
15
+ console.log(JSON.stringify({ project, component: 'pm', status: 'fail', exitCode: 3, error: msg }));
16
+ }
17
+ else {
18
+ log.error(`Fatal: ${msg}`);
19
+ }
20
+ process.exit(3);
21
+ }
22
+ const taskBackend = createTaskBackend(ctx.config);
23
+ try {
24
+ switch (subcommand) {
25
+ case 'scan': {
26
+ const state = positionals[0] || undefined;
27
+ if (state && !VALID_STATES.includes(state)) {
28
+ console.error(`Invalid state: ${state}. Valid: ${VALID_STATES.join(', ')}`);
29
+ process.exit(2);
30
+ }
31
+ const states = state ? [state] : VALID_STATES;
32
+ const allCards = [];
33
+ for (const s of states) {
34
+ const cards = await taskBackend.listByState(s);
35
+ allCards.push(...cards);
36
+ }
37
+ if (jsonOutput) {
38
+ console.log(JSON.stringify(allCards, null, 2));
39
+ }
40
+ else {
41
+ for (const card of allCards) {
42
+ const labels = card.labels.length > 0 ? ` [${card.labels.join(', ')}]` : '';
43
+ console.log(` ${card.seq.padStart(4)} | ${card.state.padEnd(11)} | ${card.name}${labels}`);
44
+ }
45
+ console.log(`\n Total: ${allCards.length} card(s)`);
46
+ }
47
+ break;
48
+ }
49
+ case 'move': {
50
+ const seq = positionals[0];
51
+ const targetState = positionals[1];
52
+ if (!seq || !targetState) {
53
+ console.error('Usage: sps pm move <project> <seq> <state>');
54
+ process.exit(2);
55
+ }
56
+ if (!VALID_STATES.includes(targetState)) {
57
+ console.error(`Invalid state: ${targetState}. Valid: ${VALID_STATES.join(', ')}`);
58
+ process.exit(2);
59
+ }
60
+ await taskBackend.move(seq, targetState);
61
+ if (jsonOutput) {
62
+ console.log(JSON.stringify({ seq, targetState, status: 'ok' }));
63
+ }
64
+ else {
65
+ log.ok(`Moved seq ${seq} → ${targetState}`);
66
+ }
67
+ break;
68
+ }
69
+ case 'comment': {
70
+ const seq = positionals[0];
71
+ const text = positionals.slice(1).join(' ');
72
+ if (!seq || !text) {
73
+ console.error('Usage: sps pm comment <project> <seq> <text>');
74
+ process.exit(2);
75
+ }
76
+ await taskBackend.comment(seq, text);
77
+ if (jsonOutput) {
78
+ console.log(JSON.stringify({ seq, status: 'ok' }));
79
+ }
80
+ else {
81
+ log.ok(`Comment added to seq ${seq}`);
82
+ }
83
+ break;
84
+ }
85
+ case 'checklist': {
86
+ const action = positionals[0]; // create, list, check, uncheck
87
+ const seq = positionals[1];
88
+ if (!action || !seq) {
89
+ console.error('Usage: sps pm checklist <create|list|check|uncheck> <project> <seq> [items...]');
90
+ process.exit(2);
91
+ }
92
+ switch (action) {
93
+ case 'create': {
94
+ const items = positionals.slice(2);
95
+ if (items.length === 0) {
96
+ console.error('Usage: sps pm checklist create <project> <seq> <item1> <item2> ...');
97
+ process.exit(2);
98
+ }
99
+ await taskBackend.checklistCreate(seq, items);
100
+ log.ok(`Checklist created for seq ${seq} (${items.length} items)`);
101
+ break;
102
+ }
103
+ case 'list': {
104
+ const items = await taskBackend.checklistList(seq);
105
+ if (jsonOutput) {
106
+ console.log(JSON.stringify(items, null, 2));
107
+ }
108
+ else {
109
+ for (const item of items) {
110
+ const icon = item.checked ? '☑' : '☐';
111
+ console.log(` ${icon} [${item.id}] ${item.text}`);
112
+ }
113
+ }
114
+ break;
115
+ }
116
+ case 'check': {
117
+ const itemId = positionals[2];
118
+ if (!itemId) {
119
+ console.error('Usage: sps pm checklist check <project> <seq> <item-id>');
120
+ process.exit(2);
121
+ }
122
+ await taskBackend.checklistCheck(seq, itemId);
123
+ log.ok(`Checked item ${itemId} on seq ${seq}`);
124
+ break;
125
+ }
126
+ case 'uncheck': {
127
+ const itemId = positionals[2];
128
+ if (!itemId) {
129
+ console.error('Usage: sps pm checklist uncheck <project> <seq> <item-id>');
130
+ process.exit(2);
131
+ }
132
+ await taskBackend.checklistUncheck(seq, itemId);
133
+ log.ok(`Unchecked item ${itemId} on seq ${seq}`);
134
+ break;
135
+ }
136
+ default:
137
+ console.error(`Unknown checklist action: ${action}`);
138
+ process.exit(2);
139
+ }
140
+ break;
141
+ }
142
+ default:
143
+ console.error(`Unknown pm subcommand: ${subcommand}`);
144
+ console.error('Available: scan, move, comment, checklist');
145
+ process.exit(2);
146
+ }
147
+ }
148
+ catch (err) {
149
+ const msg = err instanceof Error ? err.message : String(err);
150
+ if (jsonOutput) {
151
+ console.log(JSON.stringify({ project, component: 'pm', status: 'fail', error: msg }));
152
+ }
153
+ else {
154
+ log.error(msg);
155
+ }
156
+ process.exit(1);
157
+ }
158
+ }
159
+ //# sourceMappingURL=pmCommand.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pmCommand.js","sourceRoot":"","sources":["../../src/commands/pmCommand.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function executeProjectInit(project: string, flags: Record<string, boolean>): Promise<void>;
2
+ //# sourceMappingURL=projectInit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectInit.d.ts","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"AAOA,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
@@ -0,0 +1,75 @@
1
+ import { existsSync, mkdirSync, copyFileSync, writeFileSync, readFileSync, chmodSync } from 'node:fs';
2
+ import { resolve } from 'node:path';
3
+ import { Logger } from '../core/logger.js';
4
+ const HOME = process.env.HOME || '/home/coral';
5
+ const TEMPLATE_DIR = resolve(HOME, 'jarvis-skills', 'coding-work-flow', 'project-template');
6
+ export async function executeProjectInit(project, flags) {
7
+ const log = new Logger('project-init', project);
8
+ if (!project) {
9
+ log.error('Usage: sps project init <project>');
10
+ process.exit(2);
11
+ }
12
+ const instanceDir = resolve(HOME, '.projects', project);
13
+ if (existsSync(instanceDir) && !flags.force) {
14
+ log.error(`Project directory already exists: ${instanceDir}`);
15
+ log.info('Use --force to overwrite templates (conf will NOT be overwritten)');
16
+ process.exit(1);
17
+ }
18
+ // Create directory structure
19
+ const dirs = [
20
+ instanceDir,
21
+ resolve(instanceDir, 'logs'),
22
+ resolve(instanceDir, 'pm_meta'),
23
+ resolve(instanceDir, 'runtime'),
24
+ ];
25
+ for (const dir of dirs) {
26
+ if (!existsSync(dir)) {
27
+ mkdirSync(dir, { recursive: true });
28
+ log.ok(`Created ${dir}`);
29
+ }
30
+ }
31
+ // Copy batch_scheduler.sh
32
+ const schedulerSrc = resolve(TEMPLATE_DIR, 'batch_scheduler.sh');
33
+ const schedulerDst = resolve(instanceDir, 'batch_scheduler.sh');
34
+ if (existsSync(schedulerSrc)) {
35
+ copyFileSync(schedulerSrc, schedulerDst);
36
+ chmodSync(schedulerDst, 0o755);
37
+ log.ok('Installed batch_scheduler.sh (thin wrapper → sps tick)');
38
+ }
39
+ // Copy deploy.sh
40
+ const deploySrc = resolve(TEMPLATE_DIR, 'deploy.sh');
41
+ const deployDst = resolve(instanceDir, 'deploy.sh');
42
+ if (existsSync(deploySrc) && !existsSync(deployDst)) {
43
+ copyFileSync(deploySrc, deployDst);
44
+ chmodSync(deployDst, 0o755);
45
+ log.ok('Installed deploy.sh');
46
+ }
47
+ // Generate conf from template (only if conf doesn't exist)
48
+ const confDst = resolve(instanceDir, 'conf');
49
+ if (!existsSync(confDst)) {
50
+ const templateSrc = resolve(TEMPLATE_DIR, 'conf.template');
51
+ if (existsSync(templateSrc)) {
52
+ let content = readFileSync(templateSrc, 'utf-8');
53
+ content = content.replace(/__PROJECT_NAME__/g, project);
54
+ content = content.replace(/__PROJECT_DISPLAY__/g, project);
55
+ writeFileSync(confDst, content);
56
+ log.ok('Generated conf from template (edit to fill in values)');
57
+ }
58
+ }
59
+ else {
60
+ log.info('conf already exists, skipping (use --force to regenerate templates)');
61
+ }
62
+ // Create empty pipeline_order.json if not exists
63
+ const orderFile = resolve(instanceDir, 'pipeline_order.json');
64
+ if (!existsSync(orderFile)) {
65
+ writeFileSync(orderFile, '[]\n');
66
+ log.ok('Created empty pipeline_order.json');
67
+ }
68
+ log.ok(`Project ${project} initialized at ${instanceDir}`);
69
+ log.info('Next steps:');
70
+ log.info(` 1. Edit ${confDst} to fill in GitLab/PM/Notification settings`);
71
+ log.info(` 2. Run: sps doctor ${project} --fix`);
72
+ log.info(` 3. Run: sps card add ${project} "task title" "description"`);
73
+ log.info(` 4. Run: sps tick ${project}`);
74
+ }
75
+ //# sourceMappingURL=projectInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectInit.js","sourceRoot":"","sources":["../../src/commands/projectInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC;AAC/C,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,EAAE,eAAe,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;AAE5F,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,KAA8B;IAE9B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAExD,IAAI,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5C,GAAG,CAAC,KAAK,CAAC,qCAAqC,WAAW,EAAE,CAAC,CAAC;QAC9D,GAAG,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,6BAA6B;IAC7B,MAAM,IAAI,GAAG;QACX,WAAW;QACX,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC;QAC5B,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC;QAC/B,OAAO,CAAC,WAAW,EAAE,SAAS,CAAC;KAChC,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACpC,GAAG,CAAC,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;IAChE,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,YAAY,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACzC,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QAC/B,GAAG,CAAC,EAAE,CAAC,wDAAwD,CAAC,CAAC;IACnE,CAAC;IAED,iBAAiB;IACjB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACpD,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACpD,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACnC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC;IAChC,CAAC;IAED,2DAA2D;IAC3D,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;QAC3D,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAC5B,IAAI,OAAO,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;YACjD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,OAAO,CAAC,CAAC;YACxD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;YAC3D,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAChC,GAAG,CAAC,EAAE,CAAC,uDAAuD,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;IAClF,CAAC;IAED,iDAAiD;IACjD,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,qBAAqB,CAAC,CAAC;IAC9D,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,aAAa,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACjC,GAAG,CAAC,EAAE,CAAC,mCAAmC,CAAC,CAAC;IAC9C,CAAC;IAED,GAAG,CAAC,EAAE,CAAC,WAAW,OAAO,mBAAmB,WAAW,EAAE,CAAC,CAAC;IAC3D,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACxB,GAAG,CAAC,IAAI,CAAC,aAAa,OAAO,6CAA6C,CAAC,CAAC;IAC5E,GAAG,CAAC,IAAI,CAAC,wBAAwB,OAAO,QAAQ,CAAC,CAAC;IAClD,GAAG,CAAC,IAAI,CAAC,0BAA0B,OAAO,6BAA6B,CAAC,CAAC;IACzE,GAAG,CAAC,IAAI,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function executeQaTick(project: string, flags: Record<string, boolean>): Promise<void>;
2
+ //# sourceMappingURL=qaTick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qaTick.d.ts","sourceRoot":"","sources":["../../src/commands/qaTick.ts"],"names":[],"mappings":"AAKA,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -0,0 +1,43 @@
1
+ import { ProjectContext } from '../core/context.js';
2
+ import { CloseoutEngine } from '../engines/CloseoutEngine.js';
3
+ import { createTaskBackend, createWorkerProvider, createRepoBackend, createNotifier } from '../providers/registry.js';
4
+ import { Logger } from '../core/logger.js';
5
+ export async function executeQaTick(project, flags) {
6
+ const log = new Logger('qa', project);
7
+ const jsonOutput = !!flags.json;
8
+ let ctx;
9
+ try {
10
+ ctx = ProjectContext.load(project);
11
+ }
12
+ catch (err) {
13
+ const msg = err instanceof Error ? err.message : String(err);
14
+ if (jsonOutput) {
15
+ console.log(JSON.stringify({ project, component: 'qa', status: 'fail', exitCode: 3, error: msg }));
16
+ }
17
+ else {
18
+ log.error(`Fatal: ${msg}`);
19
+ }
20
+ process.exit(3);
21
+ }
22
+ const taskBackend = createTaskBackend(ctx.config);
23
+ const repoBackend = createRepoBackend(ctx.config);
24
+ const workerProvider = createWorkerProvider(ctx.config);
25
+ const notifier = createNotifier(ctx.config);
26
+ const engine = new CloseoutEngine(ctx, taskBackend, repoBackend, workerProvider, notifier);
27
+ const result = await engine.tick();
28
+ if (jsonOutput) {
29
+ console.log(JSON.stringify(result, null, 2));
30
+ }
31
+ else {
32
+ const fullLog = new Logger('qa', project, ctx.paths.logsDir);
33
+ for (const action of result.actions) {
34
+ const icon = action.result === 'ok' ? '✓' : action.result === 'skip' ? '·' : '✗';
35
+ fullLog.info(`${icon} ${action.entity}: ${action.message || action.result}`);
36
+ }
37
+ if (result.actions.length === 0) {
38
+ fullLog.info('No QA cards to process');
39
+ }
40
+ }
41
+ process.exit(result.exitCode);
42
+ }
43
+ //# sourceMappingURL=qaTick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qaTick.js","sourceRoot":"","sources":["../../src/commands/qaTick.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function executeSchedulerTick(project: string, flags: Record<string, boolean>): Promise<void>;
2
+ //# sourceMappingURL=schedulerTick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedulerTick.d.ts","sourceRoot":"","sources":["../../src/commands/schedulerTick.ts"],"names":[],"mappings":"AAKA,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -0,0 +1,45 @@
1
+ import { ProjectContext } from '../core/context.js';
2
+ import { SchedulerEngine } from '../engines/SchedulerEngine.js';
3
+ import { createTaskBackend, createNotifier } from '../providers/registry.js';
4
+ import { Logger } from '../core/logger.js';
5
+ export async function executeSchedulerTick(project, flags) {
6
+ const log = new Logger('scheduler', project);
7
+ const jsonOutput = !!flags.json;
8
+ const dryRun = !!flags['dry-run'];
9
+ let ctx;
10
+ try {
11
+ ctx = ProjectContext.load(project);
12
+ }
13
+ catch (err) {
14
+ const msg = err instanceof Error ? err.message : String(err);
15
+ if (jsonOutput) {
16
+ console.log(JSON.stringify({ project, component: 'scheduler', status: 'fail', exitCode: 3, error: msg }));
17
+ }
18
+ else {
19
+ log.error(`Fatal: ${msg}`);
20
+ }
21
+ process.exit(3);
22
+ }
23
+ const taskBackend = createTaskBackend(ctx.config);
24
+ const notifier = createNotifier(ctx.config);
25
+ const engine = new SchedulerEngine(ctx, taskBackend, notifier);
26
+ const result = await engine.tick({ dryRun });
27
+ if (jsonOutput) {
28
+ console.log(JSON.stringify(result, null, 2));
29
+ }
30
+ else {
31
+ const fullLog = new Logger('scheduler', project, ctx.paths.logsDir);
32
+ for (const action of result.actions) {
33
+ const icon = action.result === 'ok' ? '✓' : action.result === 'skip' ? '·' : '✗';
34
+ fullLog.info(`${icon} ${action.entity}: ${action.message || action.result}`);
35
+ }
36
+ if (result.actions.length === 0) {
37
+ fullLog.info('No actions taken');
38
+ if (result.details && typeof result.details === 'object' && 'reason' in result.details) {
39
+ fullLog.info(`Reason: ${result.details.reason}`);
40
+ }
41
+ }
42
+ }
43
+ process.exit(result.exitCode);
44
+ }
45
+ //# sourceMappingURL=schedulerTick.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedulerTick.js","sourceRoot":"","sources":["../../src/commands/schedulerTick.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAe,EACf,KAA8B;IAE9B,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAElC,IAAI,GAAmB,CAAC;IACxB,IAAI,CAAC;QACH,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QAC5G,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC/D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAE7C,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpE,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACjF,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;YACjC,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,QAAQ,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACvF,OAAO,CAAC,IAAI,CAAC,WAAY,MAAM,CAAC,OAAmC,CAAC,MAAM,EAAE,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Execute the unified tick command.
3
+ *
4
+ * Supports multiple projects in a single process:
5
+ * sps tick project-a project-b project-c
6
+ *
7
+ * Each project is fully isolated (own context, providers, engines, lock, state).
8
+ * Projects are ticked sequentially within each cycle. One project's error
9
+ * does not affect others.
10
+ *
11
+ * --once: single tick cycle, then exit.
12
+ */
13
+ export declare function executeTick(projects: string[], flags: Record<string, boolean>): Promise<void>;
14
+ //# sourceMappingURL=tick.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tick.d.ts","sourceRoot":"","sources":["../../src/commands/tick.ts"],"names":[],"mappings":"AAuFA;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAAE,EAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC,CAwHf"}
@@ -0,0 +1,251 @@
1
+ import { ProjectContext } from '../core/context.js';
2
+ import { acquireTickLock, releaseTickLock } from '../core/lock.js';
3
+ import { readState } from '../core/state.js';
4
+ import { Logger } from '../core/logger.js';
5
+ import { SchedulerEngine } from '../engines/SchedulerEngine.js';
6
+ import { ExecutionEngine } from '../engines/ExecutionEngine.js';
7
+ import { CloseoutEngine } from '../engines/CloseoutEngine.js';
8
+ import { MonitorEngine } from '../engines/MonitorEngine.js';
9
+ import { createTaskBackend, createWorkerProvider, createRepoBackend, createNotifier } from '../providers/registry.js';
10
+ const DEFAULT_INTERVAL_S = 30;
11
+ function createRunner(project) {
12
+ const log = new Logger('tick', project);
13
+ let ctx;
14
+ try {
15
+ ctx = ProjectContext.load(project);
16
+ }
17
+ catch (err) {
18
+ const msg = err instanceof Error ? err.message : String(err);
19
+ log.error(`Fatal: cannot load project ${project}: ${msg}`);
20
+ return null;
21
+ }
22
+ const fullLog = new Logger('tick', project, ctx.paths.logsDir);
23
+ // Acquire lock
24
+ const lockResult = acquireTickLock(ctx.paths.tickLockFile, ctx.config.TICK_LOCK_TIMEOUT_MINUTES);
25
+ if (!lockResult.acquired) {
26
+ fullLog.info('Another tick is running for this project, skipping');
27
+ return null;
28
+ }
29
+ // Create providers (each project gets its own instances)
30
+ let taskBackend, workerProvider, repoBackend, notifier;
31
+ try {
32
+ taskBackend = createTaskBackend(ctx.config);
33
+ workerProvider = createWorkerProvider(ctx.config);
34
+ repoBackend = createRepoBackend(ctx.config);
35
+ notifier = createNotifier(ctx.config);
36
+ }
37
+ catch (err) {
38
+ const msg = err instanceof Error ? err.message : String(err);
39
+ fullLog.error(`Fatal: provider init failed for ${project}: ${msg}`);
40
+ releaseTickLock(ctx.paths.tickLockFile);
41
+ return null;
42
+ }
43
+ return {
44
+ project,
45
+ ctx,
46
+ log: fullLog,
47
+ taskBackend,
48
+ notifier,
49
+ scheduler: new SchedulerEngine(ctx, taskBackend, notifier),
50
+ closeout: new CloseoutEngine(ctx, taskBackend, repoBackend, workerProvider, notifier),
51
+ execution: new ExecutionEngine(ctx, taskBackend, workerProvider, repoBackend, notifier),
52
+ monitor: new MonitorEngine(ctx, taskBackend, workerProvider, repoBackend, notifier),
53
+ done: false,
54
+ fatalError: false,
55
+ tickNum: 0,
56
+ idleCount: 0,
57
+ };
58
+ }
59
+ // ─── Entry point ─────────────────────────────────────────────────
60
+ /**
61
+ * Execute the unified tick command.
62
+ *
63
+ * Supports multiple projects in a single process:
64
+ * sps tick project-a project-b project-c
65
+ *
66
+ * Each project is fully isolated (own context, providers, engines, lock, state).
67
+ * Projects are ticked sequentially within each cycle. One project's error
68
+ * does not affect others.
69
+ *
70
+ * --once: single tick cycle, then exit.
71
+ */
72
+ export async function executeTick(projects, flags) {
73
+ const globalLog = new Logger('tick', '');
74
+ const jsonOutput = !!flags.json;
75
+ const dryRun = !!flags['dry-run'];
76
+ const once = !!flags.once;
77
+ const interval = DEFAULT_INTERVAL_S;
78
+ if (projects.length === 0) {
79
+ console.error('Usage: sps tick <project> [project2] [project3] ...');
80
+ process.exit(2);
81
+ }
82
+ // ─── Initialize runners ────────────────────────────────────────
83
+ const runners = [];
84
+ for (const project of projects) {
85
+ const runner = createRunner(project);
86
+ if (runner) {
87
+ runners.push(runner);
88
+ }
89
+ }
90
+ if (runners.length === 0) {
91
+ globalLog.error('No projects could be initialized');
92
+ process.exit(3);
93
+ }
94
+ if (runners.length > 1) {
95
+ globalLog.info(`Managing ${runners.length} projects: ${runners.map((r) => r.project).join(', ')}`);
96
+ }
97
+ // Cleanup all locks on exit
98
+ const cleanupAll = () => {
99
+ for (const runner of runners) {
100
+ releaseTickLock(runner.ctx.paths.tickLockFile);
101
+ }
102
+ };
103
+ process.on('exit', cleanupAll);
104
+ process.on('SIGINT', () => { cleanupAll(); process.exit(130); });
105
+ process.on('SIGTERM', () => { cleanupAll(); process.exit(143); });
106
+ // ─── Single tick mode ──────────────────────────────────────────
107
+ if (once) {
108
+ const results = [];
109
+ for (const runner of runners) {
110
+ const result = await runOneTick(runner, dryRun);
111
+ results.push(result);
112
+ }
113
+ if (jsonOutput) {
114
+ outputJson(runners.length === 1 ? results[0] : results);
115
+ }
116
+ cleanupAll();
117
+ const worstExit = Math.max(...results.map((r) => r.exitCode));
118
+ process.exit(worstExit);
119
+ }
120
+ // ─── Continuous mode ───────────────────────────────────────────
121
+ for (const runner of runners) {
122
+ runner.log.info(`Starting continuous tick (interval=${interval}s)`);
123
+ }
124
+ while (true) {
125
+ // Run one tick for each active project
126
+ for (const runner of runners) {
127
+ if (runner.done || runner.fatalError)
128
+ continue;
129
+ runner.tickNum++;
130
+ const result = await runOneTick(runner, dryRun);
131
+ if (jsonOutput) {
132
+ outputJson(result);
133
+ }
134
+ else {
135
+ // Compact summary
136
+ const actionsCount = result.steps.reduce((sum, s) => sum + (s.actions?.filter((a) => a.result === 'ok').length || 0), 0);
137
+ if (actionsCount > 0) {
138
+ const summary = result.steps
139
+ .flatMap((s) => (s.actions || []).filter((a) => a.result === 'ok'))
140
+ .map((a) => `${a.entity}:${a.message}`)
141
+ .join(', ');
142
+ runner.log.info(`[tick #${runner.tickNum}] ${actionsCount} action(s): ${summary}`);
143
+ runner.idleCount = 0;
144
+ }
145
+ else {
146
+ runner.idleCount++;
147
+ if (runner.idleCount === 1 || runner.idleCount % 10 === 0) {
148
+ runner.log.debug(`[tick #${runner.tickNum}] idle (${runner.idleCount})`);
149
+ }
150
+ }
151
+ }
152
+ // Check auto-stop for this project
153
+ const allDone = await checkAllDone(runner.ctx, runner.taskBackend);
154
+ if (allDone) {
155
+ runner.log.ok('All cards done, no active workers — project complete.');
156
+ await runner.notifier.sendSuccess(`[${runner.project}] Pipeline complete — all cards done.`).catch(() => { });
157
+ releaseTickLock(runner.ctx.paths.tickLockFile);
158
+ runner.done = true;
159
+ }
160
+ // Fatal error for this project
161
+ if (result.exitCode === 3) {
162
+ runner.log.error('Fatal error, stopping tick for this project');
163
+ releaseTickLock(runner.ctx.paths.tickLockFile);
164
+ runner.fatalError = true;
165
+ }
166
+ }
167
+ // Check if ALL projects are done or errored
168
+ const allFinished = runners.every((r) => r.done || r.fatalError);
169
+ if (allFinished) {
170
+ const doneCount = runners.filter((r) => r.done).length;
171
+ const errorCount = runners.filter((r) => r.fatalError).length;
172
+ if (runners.length > 1) {
173
+ globalLog.ok(`All projects finished (${doneCount} done, ${errorCount} errors)`);
174
+ }
175
+ cleanupAll();
176
+ process.exit(errorCount > 0 ? 1 : 0);
177
+ }
178
+ await sleep(interval * 1000);
179
+ }
180
+ }
181
+ // ─── Helpers ─────────────────────────────────────────────────────
182
+ async function runOneTick(runner, dryRun) {
183
+ const { project, scheduler, closeout, execution, monitor, log } = runner;
184
+ const steps = [];
185
+ const opts = { dryRun };
186
+ const schedulerResult = await runStep('scheduler', () => scheduler.tick(opts), log);
187
+ steps.push(schedulerResult);
188
+ const qaResult = await runStep('qa', () => closeout.tick(), log);
189
+ steps.push(qaResult);
190
+ let pipelineResult = await runStep('pipeline', () => execution.tick(opts), log);
191
+ if (schedulerResult.status === 'fail') {
192
+ pipelineResult.status = pipelineResult.status === 'ok' ? 'degraded' : pipelineResult.status;
193
+ pipelineResult.note = 'scheduler failed — no new cards launched';
194
+ }
195
+ steps.push(pipelineResult);
196
+ const monitorResult = await runStep('monitor', () => monitor.tick(), log);
197
+ steps.push(monitorResult);
198
+ const hasFatal = steps.some((s) => s.exitCode === 3);
199
+ const hasFail = steps.some((s) => s.status === 'fail' || s.status === 'degraded');
200
+ return {
201
+ project,
202
+ component: 'tick',
203
+ status: hasFatal ? 'fail' : hasFail ? 'degraded' : 'ok',
204
+ exitCode: hasFatal ? 3 : hasFail ? 1 : 0,
205
+ steps,
206
+ actions: [],
207
+ recommendedActions: [],
208
+ details: {},
209
+ };
210
+ }
211
+ async function checkAllDone(ctx, taskBackend) {
212
+ const pipelineLabel = ctx.config.PIPELINE_LABEL || 'AI-PIPELINE';
213
+ const state = readState(ctx.paths.stateFile, ctx.maxWorkers);
214
+ if (Object.values(state.workers).some((w) => w.status !== 'idle'))
215
+ return false;
216
+ for (const cardState of ['Planning', 'Backlog', 'Todo', 'Inprogress', 'QA']) {
217
+ try {
218
+ const cards = await taskBackend.listByState(cardState);
219
+ if (cards.some((c) => c.labels.includes(pipelineLabel)))
220
+ return false;
221
+ }
222
+ catch {
223
+ return false;
224
+ }
225
+ }
226
+ return true;
227
+ }
228
+ async function runStep(name, fn, log) {
229
+ try {
230
+ const result = await fn();
231
+ return {
232
+ step: name,
233
+ status: result.status,
234
+ exitCode: result.exitCode,
235
+ actions: result.actions,
236
+ error: result.status === 'fail' ? JSON.stringify(result.details) : undefined,
237
+ };
238
+ }
239
+ catch (err) {
240
+ const msg = err instanceof Error ? err.message : String(err);
241
+ log.error(`${name} threw: ${msg}`);
242
+ return { step: name, status: 'fail', exitCode: 1, error: msg };
243
+ }
244
+ }
245
+ function outputJson(data) {
246
+ console.log(JSON.stringify(data, null, 2));
247
+ }
248
+ function sleep(ms) {
249
+ return new Promise((resolve) => setTimeout(resolve, ms));
250
+ }
251
+ //# sourceMappingURL=tick.js.map