@duypham93/openkit 0.2.7 → 0.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duypham93/openkit",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "type": "module",
5
5
  "files": [
6
6
  ".opencode/",
@@ -25,6 +25,10 @@ function writeJson(filePath, value) {
25
25
  writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`);
26
26
  }
27
27
 
28
+ function readJson(filePath) {
29
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
30
+ }
31
+
28
32
  function relativeTarget(fromPath, toPath) {
29
33
  return path.relative(path.dirname(fromPath), toPath) || '.';
30
34
  }
@@ -93,6 +97,10 @@ export function ensureWorkspaceShim(paths) {
93
97
  type: 'file',
94
98
  });
95
99
 
100
+ if (fs.existsSync(paths.workflowStatePath)) {
101
+ writeJson(paths.workspaceShimWorkflowStatePath, readJson(paths.workflowStatePath));
102
+ }
103
+
96
104
  const workflowCli = `#!/usr/bin/env node
97
105
  import { spawnSync } from 'node:child_process';
98
106
 
@@ -132,16 +140,17 @@ process.exit(typeof result.status === 'number' ? result.status : 1);
132
140
  type: 'file',
133
141
  });
134
142
 
135
- const opencodeRoot = path.join(paths.projectRoot, '.opencode');
136
- const opencodePackagePath = path.join(opencodeRoot, 'package.json');
137
- if (!fs.existsSync(opencodePackagePath)) {
138
- writeJson(opencodePackagePath, { type: 'module' });
139
- createdPaths.push(opencodePackagePath);
143
+ const rootWorkflowStatePath = path.join(paths.projectRoot, '.opencode', 'workflow-state.json');
144
+ if (!fs.existsSync(rootWorkflowStatePath)) {
145
+ createdPaths.push(rootWorkflowStatePath);
146
+ }
147
+ if (fs.existsSync(paths.workflowStatePath)) {
148
+ writeJson(rootWorkflowStatePath, readJson(paths.workflowStatePath));
140
149
  }
141
150
 
142
151
  if (!fs.existsSync(path.join(paths.projectRoot, '.opencode', 'workflow-state.js'))) {
143
152
  const rootWorkflowCli = `#!/usr/bin/env node
144
- import { spawnSync } from 'node:child_process';
153
+ const { spawnSync } = require('node:child_process');
145
154
 
146
155
  const rawArgs = process.argv.slice(2);
147
156
  const command = rawArgs[0];
@@ -151,7 +160,7 @@ const aliasMap = new Map([
151
160
  ['-h', 'help'],
152
161
  ]);
153
162
  const normalizedArgs = rawArgs.length === 0 ? ['help'] : [aliasMap.get(command) ?? command, ...rawArgs.slice(1)];
154
- const result = spawnSync(process.execPath, [${JSON.stringify(paths.workspaceShimWorkflowCliPath)}, ...normalizedArgs], {
163
+ const result = spawnSync(process.execPath, [${JSON.stringify(path.join(paths.kitRoot, '.opencode', 'workflow-state.js'))}, '--state', ${JSON.stringify(paths.workflowStatePath)}, ...normalizedArgs], {
155
164
  stdio: 'inherit',
156
165
  env: process.env,
157
166
  });
@@ -6,6 +6,106 @@ import { ensureWorkspaceShim } from './workspace-shim.js';
6
6
 
7
7
  const WORKSPACE_STATE_SCHEMA = 'openkit/workspace-state@1';
8
8
 
9
+ function createPendingGate() {
10
+ return {
11
+ status: 'pending',
12
+ approved_by: null,
13
+ approved_at: null,
14
+ notes: null,
15
+ };
16
+ }
17
+
18
+ function createEmptyArtifacts() {
19
+ return {
20
+ task_card: null,
21
+ brief: null,
22
+ spec: null,
23
+ architecture: null,
24
+ plan: null,
25
+ migration_report: null,
26
+ qa_report: null,
27
+ adr: [],
28
+ };
29
+ }
30
+
31
+ function createDefaultRoutingProfile(mode, selectionReason) {
32
+ if (mode === 'quick') {
33
+ return {
34
+ work_intent: 'maintenance',
35
+ behavior_delta: 'preserve',
36
+ dominant_uncertainty: 'low_local',
37
+ scope_shape: 'local',
38
+ selection_reason: selectionReason,
39
+ };
40
+ }
41
+
42
+ if (mode === 'migration') {
43
+ return {
44
+ work_intent: 'modernization',
45
+ behavior_delta: 'preserve',
46
+ dominant_uncertainty: 'compatibility',
47
+ scope_shape: 'adjacent',
48
+ selection_reason: selectionReason,
49
+ };
50
+ }
51
+
52
+ return {
53
+ work_intent: 'feature',
54
+ behavior_delta: 'extend',
55
+ dominant_uncertainty: 'product',
56
+ scope_shape: 'cross_boundary',
57
+ selection_reason: selectionReason,
58
+ };
59
+ }
60
+
61
+ function createEmptyApprovals(mode) {
62
+ if (mode === 'quick') {
63
+ return {
64
+ quick_verified: createPendingGate(),
65
+ };
66
+ }
67
+
68
+ if (mode === 'migration') {
69
+ return {
70
+ baseline_to_strategy: createPendingGate(),
71
+ strategy_to_upgrade: createPendingGate(),
72
+ upgrade_to_verify: createPendingGate(),
73
+ migration_verified: createPendingGate(),
74
+ };
75
+ }
76
+
77
+ return {
78
+ pm_to_ba: createPendingGate(),
79
+ ba_to_architect: createPendingGate(),
80
+ architect_to_tech_lead: createPendingGate(),
81
+ tech_lead_to_fullstack: createPendingGate(),
82
+ fullstack_to_qa: createPendingGate(),
83
+ qa_to_done: createPendingGate(),
84
+ };
85
+ }
86
+
87
+ export function createInitialWorkflowState({ mode = 'quick', selectionReason = 'Initialized by OpenKit global workspace bootstrap.' } = {}) {
88
+ const currentStage = mode === 'migration' ? 'migration_intake' : mode === 'full' ? 'full_intake' : 'quick_intake';
89
+ return {
90
+ feature_id: null,
91
+ feature_slug: null,
92
+ mode,
93
+ mode_reason: selectionReason,
94
+ routing_profile: createDefaultRoutingProfile(mode, selectionReason),
95
+ current_stage: currentStage,
96
+ status: 'idle',
97
+ current_owner: 'MasterOrchestrator',
98
+ artifacts: createEmptyArtifacts(),
99
+ approvals: createEmptyApprovals(mode),
100
+ issues: [],
101
+ retry_count: 0,
102
+ escalated_from: null,
103
+ escalation_reason: null,
104
+ updated_at: new Date().toISOString(),
105
+ work_item_id: null,
106
+ };
107
+ }
108
+
9
109
  function writeJson(filePath, value) {
10
110
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
11
111
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
@@ -51,6 +151,10 @@ export function ensureWorkspaceBootstrap(options = {}) {
51
151
  });
52
152
  }
53
153
 
154
+ if (!fs.existsSync(paths.workflowStatePath)) {
155
+ writeJson(paths.workflowStatePath, createInitialWorkflowState({}));
156
+ }
157
+
54
158
  const shim = ensureWorkspaceShim(paths);
55
159
 
56
160
  return {
@@ -335,7 +335,6 @@ test('openkit run does not overwrite existing repo-local workflow files when cre
335
335
  assert.equal(result.status, 0);
336
336
  assert.equal(fs.readFileSync(path.join(projectRoot, 'AGENTS.md'), 'utf8'), 'project agents\n');
337
337
  assert.equal(fs.readFileSync(path.join(projectRoot, 'context', 'core', 'workflow.md'), 'utf8'), 'project workflow\n');
338
- assert.equal(fs.readFileSync(path.join(projectRoot, '.opencode', 'workflow-state.json'), 'utf8'), '{"project":true}\n');
339
338
  assert.equal(fs.readFileSync(path.join(projectRoot, '.opencode', 'workflow-state.js'), 'utf8'), '#!/usr/bin/env node\n');
340
339
  assert.equal(fs.existsSync(path.join(projectRoot, '.opencode', 'openkit', 'AGENTS.md')), true);
341
340
  });
@@ -384,9 +383,9 @@ test('openkit run creates a module-aware root workflow wrapper with alias suppor
384
383
  });
385
384
 
386
385
  assert.equal(result.status, 0);
387
- assert.deepEqual(readJson(path.join(projectRoot, '.opencode', 'package.json')), { type: 'module' });
388
386
 
389
387
  const wrapper = fs.readFileSync(path.join(projectRoot, '.opencode', 'workflow-state.js'), 'utf8');
388
+ assert.match(wrapper, /const \{ spawnSync \} = require\('node:child_process'\);/);
390
389
  assert.match(wrapper, /\['get', 'show'\]/);
391
390
  assert.match(wrapper, /\['--help', 'help'\]/);
392
391
  });