@itz4blitz/agentful 0.5.1 → 1.0.1

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/README.md CHANGED
@@ -4,29 +4,24 @@ A carrot on a stick for Claude Code
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
  [![npm version](https://badge.fury.io/js/%40itz4blitz%2Fagentful.svg)](https://www.npmjs.com/package/@itz4blitz/agentful)
7
- [![Tests](https://img.shields.io/badge/tests-370%20passing-brightgreen)](https://github.com/itz4blitz/agentful)
8
- [![Coverage](https://img.shields.io/badge/coverage-98.26%25-brightgreen)](https://github.com/itz4blitz/agentful)
7
+ [![CI Status](https://github.com/itz4blitz/agentful/actions/workflows/pipeline.yml/badge.svg)](https://github.com/itz4blitz/agentful/actions)
9
8
 
10
9
  ## Overview
11
10
 
12
- agentful is a production-ready Claude Code configuration that provides structured development through specialized AI agents. It coordinates multiple agents to implement features, write tests, and validate code quality according to a defined product specification, with human checkpoints for key decisions.
13
-
14
- **Production Quality**: Enterprise-grade testing (370 tests), 98.26% code coverage, comprehensive error handling, and lifecycle hooks for validation and metrics.
11
+ agentful is a Claude Code configuration that provides structured development through specialized AI agents. It coordinates multiple agents to implement features, write tests, and validate code quality according to a defined product specification.
15
12
 
16
13
  ## Web Configurator
17
14
 
18
15
  Configure your agentful installation with an interactive web interface:
19
16
 
20
- **[agentful.app/configure](https://agentful.app/configure)**
17
+ **[agentful.app](https://agentful.app)**
21
18
 
22
19
  - Visual component selection
23
- - 5 optimized presets
20
+ - 2 optimized presets
24
21
  - Custom configurations
25
22
  - Shareable setup URLs
26
23
  - No CLI required
27
24
 
28
- See the [Web Configurator Guide](https://agentful.app/getting-started/configurator) for details.
29
-
30
25
  ## Installation
31
26
 
32
27
  ### Default Installation (Recommended)
@@ -40,7 +35,6 @@ npx @itz4blitz/agentful init
40
35
  This installs:
41
36
  - **8 agents**: orchestrator, architect, backend, frontend, tester, reviewer, fixer, product-analyzer
42
37
  - **6 skills**: product-tracking, validation, testing, conversation, product-planning, deployment
43
- - **Hooks**: health-check (configurable)
44
38
  - **Quality gates**: types, tests, coverage, lint, security, dead-code
45
39
 
46
40
  **Tech stack is auto-detected** on first run (TypeScript, Python, React, etc.) - no need to specify.
@@ -71,17 +65,16 @@ npx @itz4blitz/agentful presets
71
65
 
72
66
  ### Shareable Configurations
73
67
 
74
- Use a configuration from [agentful.app/configure](https://agentful.app/configure):
68
+ Use a configuration from the web configurator:
75
69
 
76
70
  ```bash
77
- npx @itz4blitz/agentful init --config=https://agentful.app/c/abc12345
71
+ npx @itz4blitz/agentful init --config=<shareable-url>
78
72
  ```
79
73
 
80
74
  **Available Flags:**
81
75
  - `--preset=<name>` - Use a preset configuration
82
76
  - `--agents=<list>` - Comma-separated list of agents (orchestrator, backend, frontend, tester, reviewer, fixer, architect, product-analyzer)
83
77
  - `--skills=<list>` - Comma-separated list of skills (validation, testing, product-tracking, conversation, product-planning, deployment)
84
- - `--hooks=<list>` - Comma-separated list of hooks (health-check, typescript-validation, notifications, format-on-save)
85
78
  - `--gates=<list>` - Comma-separated list of quality gates (types, tests, coverage, lint, security, dead-code)
86
79
 
87
80
  Flags override preset values when both are specified.
@@ -196,7 +189,7 @@ For projects with existing code:
196
189
 
197
190
  ### Agent System
198
191
 
199
- agentful uses seven specialized agents:
192
+ agentful uses eight specialized agents:
200
193
 
201
194
  | Agent | Responsibility |
202
195
  |-------|---------------|
@@ -207,15 +200,16 @@ agentful uses seven specialized agents:
207
200
  | tester | Writes unit, integration, and end-to-end tests |
208
201
  | reviewer | Validates code quality, security, and standards |
209
202
  | fixer | Resolves validation failures and test errors |
203
+ | product-analyzer | Analyzes product specs for gaps, ambiguities, and readiness scoring |
210
204
 
211
205
  ### Quality Gates
212
206
 
213
- Code changes are validated against 6 core automated quality gates:
207
+ Code changes are validated against 6 automated quality gates:
214
208
 
215
209
  - Type checking (TypeScript, Flow, etc.)
216
210
  - Linting (ESLint, Biome, etc.)
217
- - Test execution (all tests must pass)
218
- - Code coverage (minimum 80%)
211
+ - Test execution
212
+ - Code coverage
219
213
  - Security scanning
220
214
  - Dead code detection
221
215
 
@@ -230,13 +224,11 @@ Runtime state is stored in `.agentful/` (gitignored, managed by npm package):
230
224
  - New projects: Starts with declared stack (`confidence: 0.4`)
231
225
  - Existing projects: Detected from code (`confidence: 0.8-1.0`)
232
226
  - Re-analyzed after first implementation in new projects
233
- - `last-validation.json` - Latest test/lint results
234
227
  - `conversation-history.json` - Session tracking
235
- - `product-analysis.json` - Readiness analysis (generated by `/agentful-product`)
236
228
 
237
229
  User configuration is stored in `.claude/` (version controlled):
238
230
 
239
- - `agents/` - Agent definitions (core + custom + ephemeral)
231
+ - `agents/` - Agent definitions
240
232
  - `commands/` - Slash commands
241
233
  - `product/` - Product specifications
242
234
  - `index.md` - Main product spec (user editable)
@@ -246,20 +238,23 @@ User configuration is stored in `.claude/` (version controlled):
246
238
  - `product-tracking/` - Progress calculation and state tracking
247
239
  - `product-planning/` - Product specification guidance
248
240
  - `validation/` - Quality gate checks and tool detection
241
+ - `testing/` - Test strategy and coverage
242
+ - `deployment/` - Deployment preparation and validation
249
243
  - `settings.json` - Project configuration
250
244
 
251
- **See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed explanation of file organization.**
252
-
253
245
  ## Commands
254
246
 
255
247
  | Command | Description |
256
248
  |---------|-------------|
249
+ | `/agentful` | Main agentful command - shows help and available commands |
257
250
  | `/agentful-product` | Smart product planning: create, analyze, and refine requirements |
258
251
  | `/agentful-start` | Start or resume structured development |
259
252
  | `/agentful-status` | Display progress and current state |
260
253
  | `/agentful-validate` | Run all quality checks |
261
254
  | `/agentful-decide` | Answer pending decisions |
262
255
  | `/agentful-update` | Smart update mechanism - fetches latest templates and gracefully migrates changes |
256
+ | `/agentful-analyze` | Analyze architecture and generate specialized agents for your tech stack |
257
+ | `/agentful-generate` | Generate specialized agents from architecture analysis |
263
258
 
264
259
  ## CI/CD Integration
265
260
 
@@ -273,7 +268,7 @@ agentful ci --generate-workflow
273
268
  agentful ci
274
269
  ```
275
270
 
276
- See `examples/` for sample workflow configurations ([GitHub Actions](examples/github-actions.yml), [GitLab CI](examples/gitlab-ci.yml), [Jenkins](examples/jenkins.groovy)).
271
+ See `examples/` for sample workflow configurations ([GitHub Actions](examples/github-actions-pipeline.yml), [GitLab CI](examples/gitlab-ci-cd.yml)).
277
272
 
278
273
  ## Remote Execution
279
274
 
@@ -290,7 +285,7 @@ agentful serve --auth=hmac --secret=$SECRET --https --cert=cert.pem --key=key.pe
290
285
  agentful serve --auth=none
291
286
  ```
292
287
 
293
- Three authentication modes: **Tailscale** (WireGuard encryption), **HMAC** (signature-based with replay protection), **SSH tunnel** (localhost-only). See `examples/server-deployment.sh` for complete deployment examples including Oracle Cloud Free Tier, Let's Encrypt SSL, and systemd service configuration.
288
+ Three authentication modes: **Tailscale** (WireGuard encryption), **HMAC** (signature-based with replay protection), **SSH tunnel** (localhost-only).
294
289
 
295
290
  ## Technology Support
296
291
 
@@ -311,13 +306,7 @@ agentful detects and adapts to your technology stack automatically:
311
306
 
312
307
  ## Documentation
313
308
 
314
- Full documentation: [agentful.app](https://agentful.app)
315
-
316
- Key guides:
317
- - [CI/CD Integration](https://agentful.app/ci-integration) - Deploy agents to production
318
- - [Quick Start](https://agentful.app/getting-started/quick-start) - Get started in 5 minutes
319
- - [Agent Architecture](https://agentful.app/concepts/architecture) - How agents work
320
- - [Commands Reference](https://agentful.app/commands) - All available commands
309
+ Documentation: [agentful.app](https://agentful.app)
321
310
 
322
311
  ## Project Structure
323
312
 
@@ -337,7 +326,6 @@ your-project/
337
326
  │ ├── completion.json
338
327
  │ ├── decisions.json
339
328
  │ ├── architecture.json
340
- │ ├── last-validation.json
341
329
  │ └── conversation-history.json
342
330
  └── src/ # Source code
343
331
  ```
@@ -350,5 +338,4 @@ MIT
350
338
 
351
339
  - GitHub: [github.com/itz4blitz/agentful](https://github.com/itz4blitz/agentful)
352
340
  - Issues: [github.com/itz4blitz/agentful/issues](https://github.com/itz4blitz/agentful/issues)
353
- - Documentation: [agentful.app](https://agentful.app)
354
- - NPM: [npmjs.com/@itz4blitz/agentful](https://www.npmjs.com/package/@itz4blitz/agentful)
341
+ - NPM: [npmjs.com/package/@itz4blitz/agentful](https://www.npmjs.com/package/@itz4blitz/agentful)
package/bin/cli.js CHANGED
@@ -996,12 +996,272 @@ async function remote(args) {
996
996
  }
997
997
  }
998
998
 
999
+ /**
1000
+ * Get PID file path
1001
+ * @returns {string} Path to PID file
1002
+ */
1003
+ function getPidFilePath() {
1004
+ return path.join(process.cwd(), '.agentful', 'server.pid');
1005
+ }
1006
+
1007
+ /**
1008
+ * Start server in daemon mode
1009
+ * @param {string[]} args - Original args
1010
+ * @param {Object} config - Server configuration
1011
+ */
1012
+ async function startDaemon(args, config) {
1013
+ const { spawn } = await import('child_process');
1014
+
1015
+ // Check if daemon is already running
1016
+ const pidFile = getPidFilePath();
1017
+ if (fs.existsSync(pidFile)) {
1018
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
1019
+
1020
+ // Check if process is still running
1021
+ try {
1022
+ process.kill(pid, 0); // Signal 0 checks if process exists
1023
+ log(colors.yellow, 'Server is already running');
1024
+ log(colors.dim, `PID: ${pid}`);
1025
+ console.log('');
1026
+ log(colors.dim, 'To stop: agentful serve --stop');
1027
+ log(colors.dim, 'To check status: agentful serve --status');
1028
+ process.exit(1);
1029
+ } catch (error) {
1030
+ // Process doesn't exist, clean up stale PID file
1031
+ fs.unlinkSync(pidFile);
1032
+ }
1033
+ }
1034
+
1035
+ // Ensure .agentful directory exists
1036
+ const agentfulDir = path.join(process.cwd(), '.agentful');
1037
+ if (!fs.existsSync(agentfulDir)) {
1038
+ fs.mkdirSync(agentfulDir, { recursive: true });
1039
+ }
1040
+
1041
+ // Prepare args for child process (remove --daemon flag)
1042
+ const childArgs = args.filter(arg => !arg.startsWith('--daemon') && arg !== '-d');
1043
+
1044
+ // Spawn detached child process
1045
+ const child = spawn(
1046
+ process.argv[0], // node executable
1047
+ [process.argv[1], 'serve', ...childArgs], // script path and args
1048
+ {
1049
+ detached: true,
1050
+ stdio: 'ignore',
1051
+ cwd: process.cwd(),
1052
+ env: {
1053
+ ...process.env,
1054
+ AGENTFUL_DAEMON: '1' // Flag to indicate we're running as daemon
1055
+ }
1056
+ }
1057
+ );
1058
+
1059
+ // Write PID file
1060
+ fs.writeFileSync(pidFile, child.pid.toString(), 'utf-8');
1061
+
1062
+ // Unref to allow parent to exit
1063
+ child.unref();
1064
+
1065
+ // Show success message
1066
+ log(colors.green, `Server started in background (PID: ${child.pid})`);
1067
+ console.log('');
1068
+ log(colors.dim, `PID file: ${pidFile}`);
1069
+ log(colors.dim, `Port: ${config.port}`);
1070
+ log(colors.dim, `Auth: ${config.auth}`);
1071
+ console.log('');
1072
+ log(colors.dim, 'Commands:');
1073
+ log(colors.dim, ' agentful serve --stop Stop the daemon');
1074
+ log(colors.dim, ' agentful serve --status Check daemon status');
1075
+ console.log('');
1076
+ }
1077
+
1078
+ /**
1079
+ * Stop daemon server
1080
+ */
1081
+ async function stopDaemon() {
1082
+ const pidFile = getPidFilePath();
1083
+
1084
+ if (!fs.existsSync(pidFile)) {
1085
+ log(colors.yellow, 'No daemon server running');
1086
+ log(colors.dim, 'PID file not found');
1087
+ process.exit(1);
1088
+ }
1089
+
1090
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
1091
+
1092
+ // Try to kill the process
1093
+ try {
1094
+ process.kill(pid, 'SIGTERM');
1095
+
1096
+ // Wait a moment for graceful shutdown
1097
+ await new Promise(resolve => setTimeout(resolve, 1000));
1098
+
1099
+ // Check if process is still running
1100
+ try {
1101
+ process.kill(pid, 0);
1102
+ // Still running, force kill
1103
+ log(colors.yellow, 'Graceful shutdown failed, forcing...');
1104
+ process.kill(pid, 'SIGKILL');
1105
+ } catch {
1106
+ // Process stopped successfully
1107
+ }
1108
+
1109
+ // Remove PID file
1110
+ fs.unlinkSync(pidFile);
1111
+
1112
+ log(colors.green, `Server stopped (PID: ${pid})`);
1113
+ } catch (error) {
1114
+ if (error.code === 'ESRCH') {
1115
+ // Process doesn't exist
1116
+ log(colors.yellow, 'Server process not found (stale PID file)');
1117
+ fs.unlinkSync(pidFile);
1118
+ } else if (error.code === 'EPERM') {
1119
+ log(colors.red, `Permission denied to kill process ${pid}`);
1120
+ log(colors.dim, 'Try: sudo agentful serve --stop');
1121
+ process.exit(1);
1122
+ } else {
1123
+ log(colors.red, `Failed to stop server: ${error.message}`);
1124
+ process.exit(1);
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ /**
1130
+ * Check daemon server status
1131
+ */
1132
+ async function checkDaemonStatus() {
1133
+ const pidFile = getPidFilePath();
1134
+
1135
+ if (!fs.existsSync(pidFile)) {
1136
+ log(colors.yellow, 'No daemon server running');
1137
+ log(colors.dim, 'PID file not found');
1138
+ console.log('');
1139
+ log(colors.dim, 'Start daemon: agentful serve --daemon');
1140
+ process.exit(1);
1141
+ }
1142
+
1143
+ const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
1144
+
1145
+ // Check if process is running
1146
+ try {
1147
+ process.kill(pid, 0); // Signal 0 just checks if process exists
1148
+
1149
+ log(colors.green, 'Server is running');
1150
+ console.log('');
1151
+ log(colors.dim, `PID: ${pid}`);
1152
+ log(colors.dim, `PID file: ${pidFile}`);
1153
+
1154
+ // Try to get more info from /proc (Linux/macOS)
1155
+ try {
1156
+ const { execSync } = await import('child_process');
1157
+ const psOutput = execSync(`ps -p ${pid} -o comm,etime,rss`, { encoding: 'utf-8' });
1158
+ const lines = psOutput.trim().split('\n');
1159
+ if (lines.length > 1) {
1160
+ const [cmd, etime, rss] = lines[1].trim().split(/\s+/);
1161
+ console.log('');
1162
+ log(colors.dim, `Uptime: ${etime}`);
1163
+ log(colors.dim, `Memory: ${Math.round(parseInt(rss) / 1024)} MB`);
1164
+ }
1165
+ } catch {
1166
+ // ps command failed, skip detailed info
1167
+ }
1168
+
1169
+ console.log('');
1170
+ log(colors.dim, 'Commands:');
1171
+ log(colors.dim, ' agentful serve --stop Stop the daemon');
1172
+ } catch (error) {
1173
+ if (error.code === 'ESRCH') {
1174
+ log(colors.yellow, 'Server not running (stale PID file)');
1175
+ log(colors.dim, `PID file exists but process ${pid} not found`);
1176
+ console.log('');
1177
+ log(colors.dim, 'Clean up: rm .agentful/server.pid');
1178
+ process.exit(1);
1179
+ } else {
1180
+ log(colors.red, `Failed to check status: ${error.message}`);
1181
+ process.exit(1);
1182
+ }
1183
+ }
1184
+ }
1185
+
999
1186
  /**
1000
1187
  * Serve command - Start remote execution server
1001
1188
  */
1002
1189
  async function serve(args) {
1003
1190
  const flags = parseFlags(args);
1004
1191
 
1192
+ // Handle --stop subcommand
1193
+ if (flags.stop) {
1194
+ return await stopDaemon();
1195
+ }
1196
+
1197
+ // Handle --status subcommand
1198
+ if (flags.status) {
1199
+ return await checkDaemonStatus();
1200
+ }
1201
+
1202
+ // Handle --help flag first
1203
+ if (flags.help || flags.h) {
1204
+ showBanner();
1205
+ log(colors.bright, 'Agentful Remote Execution Server');
1206
+ console.log('');
1207
+ log(colors.dim, 'Start a secure HTTP server for remote agent execution.');
1208
+ console.log('');
1209
+ log(colors.bright, 'USAGE:');
1210
+ console.log(` ${colors.green}agentful serve${colors.reset} ${colors.dim}[options]${colors.reset}`);
1211
+ console.log('');
1212
+ log(colors.bright, 'AUTHENTICATION MODES:');
1213
+ console.log(` ${colors.cyan}--auth=tailscale${colors.reset} ${colors.dim}(default) Tailscale network only${colors.reset}`);
1214
+ console.log(` ${colors.cyan}--auth=hmac${colors.reset} ${colors.dim}HMAC signature authentication (requires --secret)${colors.reset}`);
1215
+ console.log(` ${colors.cyan}--auth=none${colors.reset} ${colors.dim}No authentication (binds to all interfaces, use with SSH tunnel)${colors.reset}`);
1216
+ console.log('');
1217
+ log(colors.bright, 'OPTIONS:');
1218
+ console.log(` ${colors.yellow}--port=<number>${colors.reset} ${colors.dim}Server port (default: 3000)${colors.reset}`);
1219
+ console.log(` ${colors.yellow}--secret=<key>${colors.reset} ${colors.dim}HMAC secret key (required for --auth=hmac)${colors.reset}`);
1220
+ console.log(` ${colors.yellow}--https${colors.reset} ${colors.dim}Enable HTTPS (requires --cert and --key)${colors.reset}`);
1221
+ console.log(` ${colors.yellow}--cert=<path>${colors.reset} ${colors.dim}SSL certificate file path${colors.reset}`);
1222
+ console.log(` ${colors.yellow}--key=<path>${colors.reset} ${colors.dim}SSL private key file path${colors.reset}`);
1223
+ console.log(` ${colors.yellow}--daemon, -d${colors.reset} ${colors.dim}Run server in background (daemon mode)${colors.reset}`);
1224
+ console.log(` ${colors.yellow}--stop${colors.reset} ${colors.dim}Stop background server${colors.reset}`);
1225
+ console.log(` ${colors.yellow}--status${colors.reset} ${colors.dim}Check background server status${colors.reset}`);
1226
+ console.log(` ${colors.yellow}--help, -h${colors.reset} ${colors.dim}Show this help message${colors.reset}`);
1227
+ console.log('');
1228
+ log(colors.bright, 'EXAMPLES:');
1229
+ console.log('');
1230
+ log(colors.dim, ' # Start server with Tailscale auth (default)');
1231
+ console.log(` ${colors.green}agentful serve${colors.reset}`);
1232
+ console.log('');
1233
+ log(colors.dim, ' # Start server with HMAC authentication');
1234
+ console.log(` ${colors.green}agentful serve --auth=hmac --secret=your-secret-key${colors.reset}`);
1235
+ console.log('');
1236
+ log(colors.dim, ' # Start HTTPS server with HMAC auth');
1237
+ console.log(` ${colors.green}agentful serve --auth=hmac --secret=key --https --cert=cert.pem --key=key.pem${colors.reset}`);
1238
+ console.log('');
1239
+ log(colors.dim, ' # Start server without auth (public access, use SSH tunnel)');
1240
+ console.log(` ${colors.green}agentful serve --auth=none --port=3737${colors.reset}`);
1241
+ console.log('');
1242
+ log(colors.dim, ' # Start server in background (daemon mode)');
1243
+ console.log(` ${colors.green}agentful serve --daemon${colors.reset}`);
1244
+ console.log('');
1245
+ log(colors.dim, ' # Check daemon status');
1246
+ console.log(` ${colors.green}agentful serve --status${colors.reset}`);
1247
+ console.log('');
1248
+ log(colors.dim, ' # Stop daemon');
1249
+ console.log(` ${colors.green}agentful serve --stop${colors.reset}`);
1250
+ console.log('');
1251
+ log(colors.dim, ' # Generate HMAC secret');
1252
+ console.log(` ${colors.green}openssl rand -hex 32${colors.reset}`);
1253
+ console.log('');
1254
+ log(colors.dim, ' # Generate self-signed certificate');
1255
+ console.log(` ${colors.green}openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes${colors.reset}`);
1256
+ console.log('');
1257
+ log(colors.bright, 'SECURITY NOTES:');
1258
+ console.log(` ${colors.yellow}Tailscale mode:${colors.reset} Binds to 0.0.0.0, relies on Tailscale network isolation`);
1259
+ console.log(` ${colors.yellow}HMAC mode:${colors.reset} Binds to 0.0.0.0, uses cryptographic signatures (recommended for public networks)`);
1260
+ console.log(` ${colors.yellow}None mode:${colors.reset} Binds to 0.0.0.0, no authentication (use SSH tunnel: ssh -L 3000:localhost:3000 user@host)`);
1261
+ console.log('');
1262
+ return;
1263
+ }
1264
+
1005
1265
  // Parse configuration
1006
1266
  const config = {
1007
1267
  auth: flags.auth || 'tailscale',
@@ -1013,6 +1273,9 @@ async function serve(args) {
1013
1273
  projectRoot: process.cwd(),
1014
1274
  };
1015
1275
 
1276
+ // Check if --daemon flag is set
1277
+ const isDaemon = flags.daemon || flags.d;
1278
+
1016
1279
  // Validate auth mode
1017
1280
  const validAuthModes = ['tailscale', 'hmac', 'none'];
1018
1281
  if (!validAuthModes.includes(config.auth)) {
@@ -1027,8 +1290,15 @@ async function serve(args) {
1027
1290
  process.exit(1);
1028
1291
  }
1029
1292
 
1030
- // Show configuration
1031
- showBanner();
1293
+ // If daemon mode, fork the process
1294
+ if (isDaemon) {
1295
+ return await startDaemon(args, config);
1296
+ }
1297
+
1298
+ // Show configuration (skip banner if running as daemon child)
1299
+ if (!process.env.AGENTFUL_DAEMON) {
1300
+ showBanner();
1301
+ }
1032
1302
  log(colors.bright, 'Starting Agentful Server');
1033
1303
  console.log('');
1034
1304
  log(colors.dim, `Authentication: ${config.auth}`);
@@ -1036,8 +1306,8 @@ async function serve(args) {
1036
1306
  log(colors.dim, `HTTPS: ${config.https ? 'enabled' : 'disabled'}`);
1037
1307
 
1038
1308
  if (config.auth === 'none') {
1039
- log(colors.yellow, 'Warning: Server will only accept localhost connections');
1040
- log(colors.dim, 'Use SSH tunnel for remote access: ssh -L 3000:localhost:3000 user@host');
1309
+ log(colors.yellow, 'Warning: Server running with no authentication (binds to all interfaces)');
1310
+ log(colors.dim, 'Recommended: Use SSH tunnel for remote access: ssh -L 3000:localhost:3000 user@host');
1041
1311
  }
1042
1312
 
1043
1313
  if (config.auth === 'hmac' && !config.secret) {
package/lib/init.js CHANGED
@@ -91,32 +91,40 @@ export async function initProject(targetDir, config = null) {
91
91
  await fs.mkdir(agentfulDir, { recursive: true });
92
92
  createdFiles.push('.agentful/');
93
93
 
94
- // Create state.json
94
+ // Create state.json (runtime state for orchestrator)
95
95
  const stateFile = path.join(agentfulDir, 'state.json');
96
96
  const initialState = {
97
- initialized: new Date().toISOString(),
98
- version: '1.0.0',
99
- agents: [],
100
- skills: []
97
+ version: '1.0',
98
+ current_task: null,
99
+ current_phase: 'idle',
100
+ iterations: 0,
101
+ last_updated: new Date().toISOString(),
102
+ blocked_on: []
101
103
  };
102
104
  await fs.writeFile(stateFile, JSON.stringify(initialState, null, 2));
103
105
  createdFiles.push('.agentful/state.json');
104
106
 
105
- // Create completion.json
107
+ // Create completion.json (feature progress tracking)
106
108
  const completionFile = path.join(agentfulDir, 'completion.json');
107
109
  const initialCompletion = {
108
- agents: {},
109
- skills: {},
110
- lastUpdated: new Date().toISOString()
110
+ features: {},
111
+ gates: {
112
+ tests_passing: false,
113
+ no_type_errors: false,
114
+ no_dead_code: false,
115
+ coverage_80: false,
116
+ security_clean: false
117
+ },
118
+ overall_progress: 0
111
119
  };
112
120
  await fs.writeFile(completionFile, JSON.stringify(initialCompletion, null, 2));
113
121
  createdFiles.push('.agentful/completion.json');
114
122
 
115
- // Create decisions.json
123
+ // Create decisions.json (pending and resolved decisions)
116
124
  const decisionsFile = path.join(agentfulDir, 'decisions.json');
117
125
  const initialDecisions = {
118
- decisions: [],
119
- lastUpdated: new Date().toISOString()
126
+ pending: [],
127
+ resolved: []
120
128
  };
121
129
  await fs.writeFile(decisionsFile, JSON.stringify(initialDecisions, null, 2));
122
130
  createdFiles.push('.agentful/decisions.json');
@@ -133,13 +133,15 @@ ${agent.instructions}
133
133
  * @param {string} [options.projectRoot] - Project root directory
134
134
  * @param {number} [options.timeout] - Execution timeout in ms
135
135
  * @param {Object} [options.env] - Additional environment variables
136
- * @returns {Promise<Object>} Execution result
136
+ * @param {boolean} [options.async=false] - If true, return immediately with executionId
137
+ * @returns {Promise<Object>} Execution result (or just executionId if async=true)
137
138
  */
138
139
  export async function executeAgent(agentName, task, options = {}) {
139
140
  const {
140
141
  projectRoot = process.cwd(),
141
142
  timeout = 10 * 60 * 1000, // 10 minutes default
142
143
  env = {},
144
+ async = false, // New option for non-blocking execution
143
145
  } = options;
144
146
 
145
147
  // Validate agent name to prevent path traversal
@@ -176,6 +178,55 @@ export async function executeAgent(agentName, task, options = {}) {
176
178
 
177
179
  executions.set(executionId, execution);
178
180
 
181
+ // If async mode, start execution in background and return immediately
182
+ if (async) {
183
+ // Start execution in background (don't await)
184
+ runAgentExecution(executionId, agentName, task, {
185
+ projectRoot,
186
+ timeout,
187
+ filteredEnv,
188
+ }).catch((error) => {
189
+ // Update execution with error if background execution fails
190
+ const exec = executions.get(executionId);
191
+ if (exec) {
192
+ exec.state = ExecutionState.FAILED;
193
+ exec.endTime = Date.now();
194
+ exec.error = error.message;
195
+ exec.exitCode = -1;
196
+ }
197
+ });
198
+
199
+ return {
200
+ executionId,
201
+ state: ExecutionState.PENDING,
202
+ message: 'Execution started in background',
203
+ };
204
+ }
205
+
206
+ // Synchronous mode - wait for completion and return full result
207
+ return runAgentExecution(executionId, agentName, task, {
208
+ projectRoot,
209
+ timeout,
210
+ filteredEnv,
211
+ });
212
+ }
213
+
214
+ /**
215
+ * Internal function to run agent execution
216
+ * @param {string} executionId - Execution ID
217
+ * @param {string} agentName - Agent name
218
+ * @param {string} task - Task description
219
+ * @param {Object} options - Execution options
220
+ * @returns {Promise<Object>} Execution result
221
+ */
222
+ async function runAgentExecution(executionId, agentName, task, options) {
223
+ const { projectRoot, timeout, filteredEnv } = options;
224
+ const execution = executions.get(executionId);
225
+
226
+ if (!execution) {
227
+ throw new Error(`Execution ${executionId} not found`);
228
+ }
229
+
179
230
  try {
180
231
  // Load agent definition
181
232
  const agent = await loadAgentDefinition(agentName, projectRoot);
@@ -243,24 +243,28 @@ export function createServer(config = {}) {
243
243
  );
244
244
  }
245
245
 
246
- // Execute agent (non-blocking)
247
- const result = executeAgent(body.agent, body.task, {
246
+ // Log agent execution request
247
+ console.log(`[${new Date().toISOString()}] Executing agent: ${body.agent}`);
248
+ console.log(`[${new Date().toISOString()}] Task: ${body.task}`);
249
+
250
+ // Start agent execution in background (async mode)
251
+ const executionTimeout = body.timeout || 10 * 60 * 1000; // Default 10 min for execution
252
+
253
+ const result = await executeAgent(body.agent, body.task, {
248
254
  projectRoot,
249
- timeout: body.timeout,
255
+ timeout: executionTimeout,
250
256
  env: body.env,
257
+ async: true, // Return immediately with executionId
251
258
  });
252
259
 
253
- // Don't await - return immediately with execution ID
254
- result.then(() => {}).catch(() => {}); // Prevent unhandled rejection
255
-
256
- const executionId = (await result).executionId;
260
+ console.log(`[${new Date().toISOString()}] Execution started: ${result.executionId}`);
257
261
 
258
262
  res.writeHead(202, { 'Content-Type': 'application/json' });
259
263
  res.end(
260
264
  JSON.stringify({
261
- executionId,
265
+ executionId: result.executionId,
262
266
  message: 'Agent execution started',
263
- statusUrl: `/status/${executionId}`,
267
+ statusUrl: `/status/${result.executionId}`,
264
268
  })
265
269
  );
266
270
  } catch (error) {
@@ -315,6 +319,13 @@ export function createServer(config = {}) {
315
319
 
316
320
  // Request handler
317
321
  const requestHandler = (req, res) => {
322
+ const startTime = Date.now();
323
+ const clientIP = req.socket.remoteAddress;
324
+
325
+ // Log incoming request
326
+ const timestamp = new Date().toISOString();
327
+ console.log(`[${timestamp}] ${req.method} ${req.url} from ${clientIP}`);
328
+
318
329
  // Add CORS headers (restricted by default)
319
330
  if (corsOrigin) {
320
331
  res.setHeader('Access-Control-Allow-Origin', corsOrigin);
@@ -328,14 +339,27 @@ export function createServer(config = {}) {
328
339
  // Handle preflight
329
340
  if (req.method === 'OPTIONS') {
330
341
  res.writeHead(204);
342
+ const duration = Date.now() - startTime;
343
+ console.log(`[${new Date().toISOString()}] Response sent: 204 (${duration}ms)`);
331
344
  return res.end();
332
345
  }
333
346
 
334
347
  // Apply rate limiting
335
348
  if (!checkRateLimit(req, res)) {
349
+ const duration = Date.now() - startTime;
350
+ console.log(`[${new Date().toISOString()}] Response sent: 429 Rate Limited (${duration}ms)`);
336
351
  return; // Rate limit exceeded, response already sent
337
352
  }
338
353
 
354
+ // Intercept res.end to log responses
355
+ const originalEnd = res.end;
356
+ res.end = function(...args) {
357
+ const duration = Date.now() - startTime;
358
+ const statusCode = res.statusCode;
359
+ console.log(`[${new Date().toISOString()}] Response sent: ${statusCode} (${duration}ms)`);
360
+ originalEnd.apply(res, args);
361
+ };
362
+
339
363
  // Capture raw body (needed for HMAC verification)
340
364
  captureRawBody(req, res, () => {
341
365
  // Apply authentication (except for /health)
@@ -384,8 +408,9 @@ export function createServer(config = {}) {
384
408
  server = http.createServer(requestHandler);
385
409
  }
386
410
 
387
- // Determine bind address based on auth mode
388
- const host = auth === 'none' ? '127.0.0.1' : '0.0.0.0';
411
+ // Always bind to all interfaces (0.0.0.0)
412
+ // Security is enforced through authentication middleware, not binding address
413
+ const host = '0.0.0.0';
389
414
 
390
415
  return {
391
416
  start: () => {
@@ -400,7 +425,7 @@ export function createServer(config = {}) {
400
425
  console.log(`Authentication mode: ${auth}`);
401
426
 
402
427
  if (auth === 'none') {
403
- console.log('Server is bound to localhost only - use SSH tunnel for remote access');
428
+ console.log('Warning: No authentication enabled - use SSH tunnel for secure remote access');
404
429
  }
405
430
 
406
431
  // Start periodic cleanup
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itz4blitz/agentful",
3
- "version": "0.5.1",
3
+ "version": "1.0.1",
4
4
  "description": "Human-in-the-loop development kit for Claude Code with smart product analysis and natural conversation",
5
5
  "type": "module",
6
6
  "bin": {
package/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.5.0"
2
+ "version": "1.0.0"
3
3
  }