instar 0.1.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 (115) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/.claude/skills/setup-wizard/skill.md +343 -0
  3. package/.github/workflows/ci.yml +78 -0
  4. package/CLAUDE.md +82 -0
  5. package/README.md +194 -0
  6. package/dist/cli.d.ts +18 -0
  7. package/dist/cli.js +141 -0
  8. package/dist/commands/init.d.ts +40 -0
  9. package/dist/commands/init.js +568 -0
  10. package/dist/commands/job.d.ts +20 -0
  11. package/dist/commands/job.js +84 -0
  12. package/dist/commands/server.d.ts +19 -0
  13. package/dist/commands/server.js +273 -0
  14. package/dist/commands/setup.d.ts +24 -0
  15. package/dist/commands/setup.js +865 -0
  16. package/dist/commands/status.d.ts +11 -0
  17. package/dist/commands/status.js +114 -0
  18. package/dist/commands/user.d.ts +17 -0
  19. package/dist/commands/user.js +53 -0
  20. package/dist/core/Config.d.ts +16 -0
  21. package/dist/core/Config.js +144 -0
  22. package/dist/core/Prerequisites.d.ts +28 -0
  23. package/dist/core/Prerequisites.js +159 -0
  24. package/dist/core/RelationshipManager.d.ts +73 -0
  25. package/dist/core/RelationshipManager.js +318 -0
  26. package/dist/core/SessionManager.d.ts +89 -0
  27. package/dist/core/SessionManager.js +326 -0
  28. package/dist/core/StateManager.d.ts +28 -0
  29. package/dist/core/StateManager.js +96 -0
  30. package/dist/core/types.d.ts +279 -0
  31. package/dist/core/types.js +8 -0
  32. package/dist/index.d.ts +18 -0
  33. package/dist/index.js +23 -0
  34. package/dist/messaging/TelegramAdapter.d.ts +73 -0
  35. package/dist/messaging/TelegramAdapter.js +288 -0
  36. package/dist/monitoring/HealthChecker.d.ts +38 -0
  37. package/dist/monitoring/HealthChecker.js +148 -0
  38. package/dist/scaffold/bootstrap.d.ts +21 -0
  39. package/dist/scaffold/bootstrap.js +110 -0
  40. package/dist/scaffold/templates.d.ts +34 -0
  41. package/dist/scaffold/templates.js +187 -0
  42. package/dist/scheduler/JobLoader.d.ts +18 -0
  43. package/dist/scheduler/JobLoader.js +70 -0
  44. package/dist/scheduler/JobScheduler.d.ts +111 -0
  45. package/dist/scheduler/JobScheduler.js +402 -0
  46. package/dist/server/AgentServer.d.ts +40 -0
  47. package/dist/server/AgentServer.js +73 -0
  48. package/dist/server/middleware.d.ts +12 -0
  49. package/dist/server/middleware.js +50 -0
  50. package/dist/server/routes.d.ts +25 -0
  51. package/dist/server/routes.js +224 -0
  52. package/dist/users/UserManager.d.ts +45 -0
  53. package/dist/users/UserManager.js +113 -0
  54. package/docs/dawn-audit-report.md +412 -0
  55. package/docs/positioning-vs-openclaw.md +246 -0
  56. package/package.json +52 -0
  57. package/src/cli.ts +169 -0
  58. package/src/commands/init.ts +654 -0
  59. package/src/commands/job.ts +110 -0
  60. package/src/commands/server.ts +325 -0
  61. package/src/commands/setup.ts +958 -0
  62. package/src/commands/status.ts +125 -0
  63. package/src/commands/user.ts +71 -0
  64. package/src/core/Config.ts +161 -0
  65. package/src/core/Prerequisites.ts +187 -0
  66. package/src/core/RelationshipManager.ts +366 -0
  67. package/src/core/SessionManager.ts +385 -0
  68. package/src/core/StateManager.ts +121 -0
  69. package/src/core/types.ts +320 -0
  70. package/src/index.ts +58 -0
  71. package/src/messaging/TelegramAdapter.ts +365 -0
  72. package/src/monitoring/HealthChecker.ts +172 -0
  73. package/src/scaffold/bootstrap.ts +122 -0
  74. package/src/scaffold/templates.ts +204 -0
  75. package/src/scheduler/JobLoader.ts +85 -0
  76. package/src/scheduler/JobScheduler.ts +476 -0
  77. package/src/server/AgentServer.ts +93 -0
  78. package/src/server/middleware.ts +58 -0
  79. package/src/server/routes.ts +278 -0
  80. package/src/templates/default-jobs.json +47 -0
  81. package/src/templates/hooks/compaction-recovery.sh +23 -0
  82. package/src/templates/hooks/dangerous-command-guard.sh +35 -0
  83. package/src/templates/hooks/grounding-before-messaging.sh +22 -0
  84. package/src/templates/hooks/session-start.sh +37 -0
  85. package/src/templates/hooks/settings-template.json +45 -0
  86. package/src/templates/scripts/health-watchdog.sh +63 -0
  87. package/src/templates/scripts/telegram-reply.sh +54 -0
  88. package/src/users/UserManager.ts +129 -0
  89. package/tests/e2e/lifecycle.test.ts +376 -0
  90. package/tests/fixtures/test-repo/CLAUDE.md +3 -0
  91. package/tests/fixtures/test-repo/README.md +1 -0
  92. package/tests/helpers/setup.ts +209 -0
  93. package/tests/integration/fresh-install.test.ts +218 -0
  94. package/tests/integration/scheduler-basic.test.ts +109 -0
  95. package/tests/integration/server-full.test.ts +284 -0
  96. package/tests/integration/session-lifecycle.test.ts +181 -0
  97. package/tests/unit/Config.test.ts +22 -0
  98. package/tests/unit/HealthChecker.test.ts +168 -0
  99. package/tests/unit/JobLoader.test.ts +151 -0
  100. package/tests/unit/JobScheduler.test.ts +267 -0
  101. package/tests/unit/Prerequisites.test.ts +59 -0
  102. package/tests/unit/RelationshipManager.test.ts +345 -0
  103. package/tests/unit/StateManager.test.ts +143 -0
  104. package/tests/unit/TelegramAdapter.test.ts +165 -0
  105. package/tests/unit/UserManager.test.ts +131 -0
  106. package/tests/unit/bootstrap.test.ts +28 -0
  107. package/tests/unit/commands.test.ts +138 -0
  108. package/tests/unit/middleware.test.ts +92 -0
  109. package/tests/unit/relationship-routes.test.ts +131 -0
  110. package/tests/unit/scaffold-templates.test.ts +132 -0
  111. package/tests/unit/server.test.ts +163 -0
  112. package/tsconfig.json +20 -0
  113. package/vitest.config.ts +9 -0
  114. package/vitest.e2e.config.ts +9 -0
  115. package/vitest.integration.config.ts +9 -0
@@ -0,0 +1,163 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import request from 'supertest';
3
+ import { AgentServer } from '../../src/server/AgentServer.js';
4
+ import { createTempProject, createMockSessionManager } from '../helpers/setup.js';
5
+ import type { TempProject, MockSessionManager } from '../helpers/setup.js';
6
+ import type { AgentKitConfig } from '../../src/core/types.js';
7
+
8
+ describe('AgentServer', () => {
9
+ let project: TempProject;
10
+ let mockSM: MockSessionManager;
11
+ let server: AgentServer;
12
+ let app: ReturnType<AgentServer['getApp']>;
13
+
14
+ const fakeConfig: AgentKitConfig = {
15
+ projectName: 'test-project',
16
+ projectDir: '/tmp/test',
17
+ stateDir: '/tmp/test/.instar',
18
+ port: 0, // not actually listening in tests
19
+ sessions: {
20
+ tmuxPath: '/usr/bin/tmux',
21
+ claudePath: '/usr/bin/claude',
22
+ projectDir: '/tmp/test',
23
+ maxSessions: 3,
24
+ protectedSessions: [],
25
+ completionPatterns: [],
26
+ },
27
+ scheduler: {
28
+ jobsFile: '',
29
+ enabled: false,
30
+ maxParallelJobs: 2,
31
+ quotaThresholds: { normal: 50, elevated: 70, critical: 85, shutdown: 95 },
32
+ },
33
+ users: [],
34
+ messaging: [],
35
+ monitoring: {
36
+ quotaTracking: false,
37
+ memoryMonitoring: false,
38
+ healthCheckIntervalMs: 30000,
39
+ },
40
+ };
41
+
42
+ beforeAll(() => {
43
+ project = createTempProject();
44
+ mockSM = createMockSessionManager();
45
+
46
+ server = new AgentServer({
47
+ config: fakeConfig,
48
+ sessionManager: mockSM as any,
49
+ state: project.state,
50
+ });
51
+ app = server.getApp();
52
+ });
53
+
54
+ afterAll(() => {
55
+ project.cleanup();
56
+ });
57
+
58
+ describe('GET /health', () => {
59
+ it('returns ok status', async () => {
60
+ const res = await request(app).get('/health');
61
+ expect(res.status).toBe(200);
62
+ expect(res.body.status).toBe('ok');
63
+ expect(res.body.project).toBe('test-project');
64
+ expect(res.body).toHaveProperty('uptime');
65
+ expect(res.body).toHaveProperty('uptimeHuman');
66
+ expect(res.body).toHaveProperty('version');
67
+ });
68
+ });
69
+
70
+ describe('GET /status', () => {
71
+ it('returns session and scheduler info', async () => {
72
+ const res = await request(app).get('/status');
73
+ expect(res.status).toBe(200);
74
+ expect(res.body.sessions).toHaveProperty('running');
75
+ expect(res.body.sessions).toHaveProperty('max');
76
+ expect(res.body.scheduler).toBeNull(); // No scheduler provided
77
+ });
78
+ });
79
+
80
+ describe('GET /sessions', () => {
81
+ it('returns empty array when no sessions', async () => {
82
+ const res = await request(app).get('/sessions');
83
+ expect(res.status).toBe(200);
84
+ expect(res.body).toEqual([]);
85
+ });
86
+ });
87
+
88
+ describe('GET /sessions/:name/output', () => {
89
+ it('returns output for valid session', async () => {
90
+ // captureOutput returns 'mock output' for any session
91
+ const res = await request(app).get('/sessions/test-session/output');
92
+ expect(res.status).toBe(200);
93
+ expect(res.body).toHaveProperty('output');
94
+ });
95
+ });
96
+
97
+ describe('POST /sessions/:name/input', () => {
98
+ it('rejects missing text', async () => {
99
+ const res = await request(app)
100
+ .post('/sessions/test-session/input')
101
+ .send({});
102
+ expect(res.status).toBe(400);
103
+ expect(res.body.error).toContain('text');
104
+ });
105
+
106
+ it('returns 404 for non-running session', async () => {
107
+ // sendInput returns false when session not in aliveSet
108
+ const res = await request(app)
109
+ .post('/sessions/nonexistent/input')
110
+ .send({ text: 'hello' });
111
+ expect(res.status).toBe(404);
112
+ });
113
+ });
114
+
115
+ describe('POST /sessions/spawn', () => {
116
+ it('rejects missing required fields', async () => {
117
+ const res = await request(app)
118
+ .post('/sessions/spawn')
119
+ .send({ name: 'test' });
120
+ expect(res.status).toBe(400);
121
+ expect(res.body.error).toContain('required');
122
+ });
123
+ });
124
+
125
+ describe('GET /jobs', () => {
126
+ it('returns empty when no scheduler', async () => {
127
+ const res = await request(app).get('/jobs');
128
+ expect(res.status).toBe(200);
129
+ expect(res.body.jobs).toEqual([]);
130
+ expect(res.body.scheduler).toBeNull();
131
+ });
132
+ });
133
+
134
+ describe('POST /jobs/:slug/trigger', () => {
135
+ it('returns 503 when no scheduler', async () => {
136
+ const res = await request(app)
137
+ .post('/jobs/test-job/trigger')
138
+ .send({});
139
+ expect(res.status).toBe(503);
140
+ });
141
+ });
142
+
143
+ describe('GET /events', () => {
144
+ it('returns events', async () => {
145
+ project.state.appendEvent({
146
+ type: 'test',
147
+ summary: 'Test event',
148
+ timestamp: new Date().toISOString(),
149
+ });
150
+
151
+ const res = await request(app).get('/events');
152
+ expect(res.status).toBe(200);
153
+ expect(res.body.length).toBeGreaterThanOrEqual(1);
154
+ });
155
+ });
156
+
157
+ describe('error handling', () => {
158
+ it('DELETE /sessions/:id returns 404 for unknown session', async () => {
159
+ const res = await request(app).delete('/sessions/nonexistent');
160
+ expect(res.status).toBe(404);
161
+ });
162
+ });
163
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "lib": ["ES2022"],
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "resolveJsonModule": true,
14
+ "declaration": true,
15
+ "declarationMap": true,
16
+ "sourceMap": true
17
+ },
18
+ "include": ["src/**/*"],
19
+ "exclude": ["node_modules", "dist", "tests"]
20
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['tests/unit/**/*.test.ts'],
6
+ environment: 'node',
7
+ testTimeout: 10000,
8
+ },
9
+ });
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['tests/e2e/**/*.test.ts'],
6
+ environment: 'node',
7
+ testTimeout: 60000, // E2E tests may involve real sessions + cron waits
8
+ },
9
+ });
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ include: ['tests/integration/**/*.test.ts'],
6
+ environment: 'node',
7
+ testTimeout: 60000, // Integration tests may spawn real sessions
8
+ },
9
+ });