aiwcli 0.10.2 → 0.10.3
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/dist/commands/clear.d.ts +11 -6
- package/dist/commands/clear.js +200 -249
- package/dist/commands/init/index.d.ts +1 -17
- package/dist/commands/init/index.js +19 -104
- package/dist/lib/template-installer.d.ts +7 -12
- package/dist/lib/template-installer.js +69 -193
- package/dist/lib/template-settings-reconstructor.d.ts +35 -0
- package/dist/lib/template-settings-reconstructor.js +130 -0
- package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/archive_plan.py +10 -2
- package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/hook_utils.py +8 -10
- package/dist/templates/_shared/lib/base/inference.py +51 -62
- package/dist/templates/_shared/lib/base/logger.py +35 -21
- package/dist/templates/_shared/lib/base/stop_words.py +8 -0
- package/dist/templates/_shared/lib/base/utils.py +29 -8
- package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/plan_manager.py +101 -2
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -0
- package/dist/templates/_shared/lib-ts/base/constants.ts +299 -0
- package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -0
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +360 -0
- package/dist/templates/_shared/lib-ts/base/inference.ts +245 -0
- package/dist/templates/_shared/lib-ts/base/logger.ts +234 -0
- package/dist/templates/_shared/lib-ts/base/state-io.ts +114 -0
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -0
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +23 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +184 -0
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +432 -0
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +497 -0
- package/dist/templates/_shared/lib-ts/context/context-store.ts +679 -0
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +292 -0
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +181 -0
- package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +215 -0
- package/dist/templates/_shared/lib-ts/package.json +21 -0
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +102 -0
- package/dist/templates/_shared/lib-ts/templates/plan-context.ts +65 -0
- package/dist/templates/_shared/lib-ts/tsconfig.json +13 -0
- package/dist/templates/_shared/lib-ts/types.ts +151 -0
- package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
- package/dist/templates/_shared/scripts/save_handoff.ts +359 -0
- package/dist/templates/_shared/scripts/status_line.py +17 -2
- package/dist/templates/cc-native/_cc-native/agents/ARCH-EVOLUTION.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/ARCH-PATTERNS.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/ARCH-STRUCTURE.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/{ASSUMPTION-CHAIN-TRACER.md → ASSUMPTION-TRACER.md} +6 -10
- package/dist/templates/cc-native/_cc-native/agents/CLARITY-AUDITOR.md +6 -10
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +74 -1
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-FEASIBILITY.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-GAPS.md +71 -0
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-ORDERING.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/CONSTRAINT-VALIDATOR.md +73 -0
- package/dist/templates/cc-native/_cc-native/agents/DESIGN-ADR-VALIDATOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/DESIGN-SCALE-MATCHER.md +65 -0
- package/dist/templates/cc-native/_cc-native/agents/DEVILS-ADVOCATE.md +6 -9
- package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-PHILOSOPHY.md +87 -0
- package/dist/templates/cc-native/_cc-native/agents/HANDOFF-READINESS.md +5 -9
- package/dist/templates/cc-native/_cc-native/agents/{HIDDEN-COMPLEXITY-DETECTOR.md → HIDDEN-COMPLEXITY.md} +6 -10
- package/dist/templates/cc-native/_cc-native/agents/INCREMENTAL-DELIVERY.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +91 -18
- package/dist/templates/cc-native/_cc-native/agents/RISK-DEPENDENCY.md +63 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-FMEA.md +67 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-PREMORTEM.md +72 -0
- package/dist/templates/cc-native/_cc-native/agents/RISK-REVERSIBILITY.md +75 -0
- package/dist/templates/cc-native/_cc-native/agents/SCOPE-BOUNDARY.md +78 -0
- package/dist/templates/cc-native/_cc-native/agents/SIMPLICITY-GUARDIAN.md +5 -9
- package/dist/templates/cc-native/_cc-native/agents/SKEPTIC.md +16 -12
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-BEHAVIOR-AUDITOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-CHARACTERIZATION.md +72 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-FIRST-VALIDATOR.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-PYRAMID-ANALYZER.md +62 -0
- package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-COSTS.md +68 -0
- package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-STAKEHOLDERS.md +66 -0
- package/dist/templates/cc-native/_cc-native/agents/VERIFY-COVERAGE.md +75 -0
- package/dist/templates/cc-native/_cc-native/agents/VERIFY-STRENGTH.md +70 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +125 -40
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/utils.py +57 -13
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +11 -7
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/dist/lib/template-merger.d.ts +0 -47
- package/dist/lib/template-merger.js +0 -162
- package/dist/templates/cc-native/_cc-native/agents/ACCESSIBILITY-TESTER.md +0 -79
- package/dist/templates/cc-native/_cc-native/agents/ARCHITECT-REVIEWER.md +0 -48
- package/dist/templates/cc-native/_cc-native/agents/CODE-REVIEWER.md +0 -70
- package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-CHECKER.md +0 -59
- package/dist/templates/cc-native/_cc-native/agents/CONTEXT-EXTRACTOR.md +0 -92
- package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-REVIEWER.md +0 -51
- package/dist/templates/cc-native/_cc-native/agents/FEASIBILITY-ANALYST.md +0 -57
- package/dist/templates/cc-native/_cc-native/agents/FRESH-PERSPECTIVE.md +0 -54
- package/dist/templates/cc-native/_cc-native/agents/INCENTIVE-MAPPER.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/PENETRATION-TESTER.md +0 -79
- package/dist/templates/cc-native/_cc-native/agents/PERFORMANCE-ENGINEER.md +0 -75
- package/dist/templates/cc-native/_cc-native/agents/PRECEDENT-FINDER.md +0 -70
- package/dist/templates/cc-native/_cc-native/agents/REVERSIBILITY-ANALYST.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/RISK-ASSESSOR.md +0 -58
- package/dist/templates/cc-native/_cc-native/agents/SECOND-ORDER-ANALYST.md +0 -61
- package/dist/templates/cc-native/_cc-native/agents/STAKEHOLDER-ADVOCATE.md +0 -55
- package/dist/templates/cc-native/_cc-native/agents/TRADE-OFF-ILLUMINATOR.md +0 -204
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified logging for all hooks and libraries.
|
|
3
|
+
*
|
|
4
|
+
* Log format: JSONL (one JSON object per line)
|
|
5
|
+
* Log location: _output/hook-log.jsonl (global, all sessions)
|
|
6
|
+
* Filter by session using the "sid" field.
|
|
7
|
+
*
|
|
8
|
+
* Environment variables:
|
|
9
|
+
* - HOOK_LOG_DISABLE=1: Disable all file logging
|
|
10
|
+
* - HOOK_LOG_LEVEL=warn: Minimum level to log (default: debug)
|
|
11
|
+
* - HOOK_ERROR_LOG_DISABLE=1: Legacy alias for HOOK_LOG_DISABLE
|
|
12
|
+
*
|
|
13
|
+
* Never throws. No buffering. Stdlib only.
|
|
14
|
+
* See SPEC.md §3
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import * as fs from "node:fs";
|
|
18
|
+
import * as path from "node:path";
|
|
19
|
+
|
|
20
|
+
const LEVELS: Record<string, number> = {
|
|
21
|
+
debug: 0,
|
|
22
|
+
info: 1,
|
|
23
|
+
warn: 2,
|
|
24
|
+
error: 3,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const MAX_LOG_LINES = 10_000; // Max lines in global log before pruning
|
|
28
|
+
|
|
29
|
+
// Module-level session ID cache
|
|
30
|
+
let _cachedSessionId: string | null = null;
|
|
31
|
+
|
|
32
|
+
// Module-level context path cache (kept for external callers)
|
|
33
|
+
let _cachedContextPath: string | null = null;
|
|
34
|
+
let _contextResolved = false;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Set the session ID for this process. All subsequent log calls include it.
|
|
38
|
+
*/
|
|
39
|
+
export function setSessionId(sessionId: string | null): void {
|
|
40
|
+
_cachedSessionId = sessionId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set the context path for this process. Kept for external callers.
|
|
45
|
+
*/
|
|
46
|
+
export function setContextPath(contextPath: string | null): void {
|
|
47
|
+
_cachedContextPath = contextPath;
|
|
48
|
+
_contextResolved = true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getContextPath(): string | null {
|
|
52
|
+
if (!_contextResolved) {
|
|
53
|
+
_contextResolved = true; // Don't retry
|
|
54
|
+
}
|
|
55
|
+
return _cachedContextPath;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getMinLevel(): number {
|
|
59
|
+
const env = (process.env.HOOK_LOG_LEVEL ?? "debug").toLowerCase();
|
|
60
|
+
return LEVELS[env] ?? 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isDisabled(): boolean {
|
|
64
|
+
return (
|
|
65
|
+
process.env.HOOK_LOG_DISABLE === "1" ||
|
|
66
|
+
process.env.HOOK_ERROR_LOG_DISABLE === "1" ||
|
|
67
|
+
process.env.CCNATIVE_DEBUG_DISABLE === "1"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getProjectRoot(): string {
|
|
72
|
+
return process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Write a structured log entry to the global hook log.
|
|
77
|
+
*
|
|
78
|
+
* All entries go to _output/hook-log.jsonl. Use the "sid" field
|
|
79
|
+
* (set via setSessionId) to filter by session.
|
|
80
|
+
*/
|
|
81
|
+
export function hookLog(
|
|
82
|
+
level: string,
|
|
83
|
+
hookName: string,
|
|
84
|
+
message: string,
|
|
85
|
+
opts?: {
|
|
86
|
+
component?: string;
|
|
87
|
+
data?: any;
|
|
88
|
+
traceback_str?: string;
|
|
89
|
+
stderr?: boolean;
|
|
90
|
+
},
|
|
91
|
+
): void {
|
|
92
|
+
try {
|
|
93
|
+
const levelLower = level.toLowerCase();
|
|
94
|
+
const levelNum = LEVELS[levelLower] ?? 0;
|
|
95
|
+
const component = opts?.component ?? "";
|
|
96
|
+
const tracebackStr = opts?.traceback_str ?? "";
|
|
97
|
+
const stderrEnabled = opts?.stderr !== false;
|
|
98
|
+
|
|
99
|
+
// Write to stderr
|
|
100
|
+
if (stderrEnabled) {
|
|
101
|
+
const prefix = component
|
|
102
|
+
? `[${hookName}:${component}]`
|
|
103
|
+
: `[${hookName}]`;
|
|
104
|
+
process.stderr.write(`${prefix} ${message}\n`);
|
|
105
|
+
if (tracebackStr) {
|
|
106
|
+
process.stderr.write(tracebackStr + "\n");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Check if file logging is enabled
|
|
111
|
+
if (isDisabled()) return;
|
|
112
|
+
|
|
113
|
+
// Check minimum level
|
|
114
|
+
if (levelNum < getMinLevel()) return;
|
|
115
|
+
|
|
116
|
+
// Build JSONL entry
|
|
117
|
+
const now = new Date();
|
|
118
|
+
const ts = now.toISOString().replace("Z", "").slice(0, 23);
|
|
119
|
+
const entry: Record<string, any> = {
|
|
120
|
+
ts,
|
|
121
|
+
level: levelLower,
|
|
122
|
+
hook: hookName,
|
|
123
|
+
msg: message,
|
|
124
|
+
};
|
|
125
|
+
if (_cachedSessionId) entry.sid = _cachedSessionId;
|
|
126
|
+
if (component) entry.component = component;
|
|
127
|
+
if (opts?.data !== undefined && opts.data !== null) {
|
|
128
|
+
try {
|
|
129
|
+
JSON.stringify(opts.data);
|
|
130
|
+
entry.data = opts.data;
|
|
131
|
+
} catch {
|
|
132
|
+
entry.data = String(opts.data);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (tracebackStr) entry.tb = tracebackStr.trimEnd();
|
|
136
|
+
|
|
137
|
+
const line = JSON.stringify(entry) + "\n";
|
|
138
|
+
|
|
139
|
+
// Always write to global log
|
|
140
|
+
const logPath = path.join(getProjectRoot(), "_output", "hook-log.jsonl");
|
|
141
|
+
|
|
142
|
+
// Ensure directory exists
|
|
143
|
+
const dir = path.dirname(logPath);
|
|
144
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
145
|
+
|
|
146
|
+
// Line-count guard: prune to last MAX_LOG_LINES
|
|
147
|
+
try {
|
|
148
|
+
if (fs.existsSync(logPath)) {
|
|
149
|
+
const content = fs.readFileSync(logPath, "utf-8");
|
|
150
|
+
const lines = content.split("\n");
|
|
151
|
+
if (lines.length > MAX_LOG_LINES) {
|
|
152
|
+
fs.writeFileSync(
|
|
153
|
+
logPath,
|
|
154
|
+
lines.slice(lines.length - MAX_LOG_LINES).join("\n"),
|
|
155
|
+
"utf-8",
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
// ignore
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
fs.appendFileSync(logPath, line, "utf-8");
|
|
164
|
+
} catch {
|
|
165
|
+
// Never crash
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export function logDebug(hookName: string, message: string, opts?: Record<string, any>): void {
|
|
170
|
+
hookLog("debug", hookName, message, opts);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function logInfo(hookName: string, message: string, opts?: Record<string, any>): void {
|
|
174
|
+
hookLog("info", hookName, message, opts);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function logWarn(hookName: string, message: string, opts?: Record<string, any>): void {
|
|
178
|
+
hookLog("warn", hookName, message, opts);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function logError(hookName: string, message: string, opts?: Record<string, any>): void {
|
|
182
|
+
hookLog("error", hookName, message, opts);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Log a structured diagnostic entry at a hook decision point.
|
|
187
|
+
* See SPEC.md §3.8
|
|
188
|
+
*/
|
|
189
|
+
export function logDiagnostic(
|
|
190
|
+
hookName: string,
|
|
191
|
+
phase: string,
|
|
192
|
+
summary: string,
|
|
193
|
+
opts?: {
|
|
194
|
+
inputs?: any;
|
|
195
|
+
decision?: any;
|
|
196
|
+
reasoning?: any;
|
|
197
|
+
component?: string;
|
|
198
|
+
data?: any;
|
|
199
|
+
},
|
|
200
|
+
): void {
|
|
201
|
+
const diagData: Record<string, any> = { phase };
|
|
202
|
+
if (opts?.inputs !== undefined) diagData.inputs = opts.inputs;
|
|
203
|
+
if (opts?.decision !== undefined) diagData.decision = opts.decision;
|
|
204
|
+
if (opts?.reasoning !== undefined) diagData.reasoning = opts.reasoning;
|
|
205
|
+
if (opts?.data && typeof opts.data === "object") {
|
|
206
|
+
Object.assign(diagData, opts.data);
|
|
207
|
+
}
|
|
208
|
+
hookLog("debug", hookName, `[DIAG:${phase}] ${summary}`, {
|
|
209
|
+
component: opts?.component ?? "diag",
|
|
210
|
+
data: diagData,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Backward-compatible wrapper matching old hook_utils.log_hook_error signature.
|
|
216
|
+
* See SPEC.md §3.6
|
|
217
|
+
*/
|
|
218
|
+
export function logHookError(
|
|
219
|
+
hookName: string,
|
|
220
|
+
error: Error | string,
|
|
221
|
+
hookEvent = "unknown",
|
|
222
|
+
tracebackStr = "",
|
|
223
|
+
): void {
|
|
224
|
+
const errStr = typeof error === "string" ? error : String(error);
|
|
225
|
+
const msg = errStr.replace(/[\n\r]/g, " ").slice(0, 200);
|
|
226
|
+
const errType =
|
|
227
|
+
typeof error === "object" && error !== null
|
|
228
|
+
? error.constructor.name
|
|
229
|
+
: "Error";
|
|
230
|
+
hookLog("error", hookName, `[${hookEvent}] ${errType}: ${msg}`, {
|
|
231
|
+
traceback_str: tracebackStr,
|
|
232
|
+
stderr: true,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared I/O for state.json — read, write, serialize.
|
|
3
|
+
* Extracted to avoid circular deps between context-store and task-tracker.
|
|
4
|
+
* See SPEC.md §7.1
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as fs from "node:fs";
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { getContextDir } from "./constants.js";
|
|
10
|
+
import { atomicWrite } from "./atomic-write.js";
|
|
11
|
+
import { logWarn } from "./logger.js";
|
|
12
|
+
import type { ContextState, Mode } from "../types.js";
|
|
13
|
+
|
|
14
|
+
/** Mode migration from legacy context_manager values. */
|
|
15
|
+
const MODE_MIGRATION: Record<string, Mode> = {
|
|
16
|
+
none: "idle",
|
|
17
|
+
planning: "idle",
|
|
18
|
+
pending_implementation: "has_plan",
|
|
19
|
+
implementing: "active",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Serialize a ContextState for JSON output.
|
|
24
|
+
* Omits null/undefined keys but keeps false, 0, empty string, and empty arrays.
|
|
25
|
+
*/
|
|
26
|
+
export function toDict(state: ContextState): Record<string, unknown> {
|
|
27
|
+
const result: Record<string, unknown> = {};
|
|
28
|
+
for (const [key, value] of Object.entries(state)) {
|
|
29
|
+
if (value !== null && value !== undefined) {
|
|
30
|
+
result[key] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get path to state.json for a context.
|
|
38
|
+
*/
|
|
39
|
+
export function statePath(contextId: string, projectRoot?: string): string {
|
|
40
|
+
return path.join(getContextDir(contextId, projectRoot), "state.json");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Read and parse state.json for a context.
|
|
45
|
+
* Applies legacy mode migration. Returns null if file doesn't exist or is corrupt.
|
|
46
|
+
*/
|
|
47
|
+
export function readStateJson(
|
|
48
|
+
contextId: string,
|
|
49
|
+
projectRoot?: string,
|
|
50
|
+
): ContextState | null {
|
|
51
|
+
const sp = statePath(contextId, projectRoot);
|
|
52
|
+
if (!fs.existsSync(sp)) return null;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const raw = fs.readFileSync(sp, "utf-8");
|
|
56
|
+
const data = JSON.parse(raw) as Record<string, any>;
|
|
57
|
+
return dictToState(data);
|
|
58
|
+
} catch (e: any) {
|
|
59
|
+
logWarn("state_io", `Failed to read state.json for '${contextId}': ${e}`);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Atomically write state.json for a context.
|
|
66
|
+
* Returns [success, error].
|
|
67
|
+
*/
|
|
68
|
+
export function writeStateJson(
|
|
69
|
+
contextId: string,
|
|
70
|
+
state: ContextState,
|
|
71
|
+
projectRoot?: string,
|
|
72
|
+
): [boolean, string | null] {
|
|
73
|
+
const sp = statePath(contextId, projectRoot);
|
|
74
|
+
const dir = path.dirname(sp);
|
|
75
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
|
|
77
|
+
const content = JSON.stringify(toDict(state), null, 2);
|
|
78
|
+
return atomicWrite(sp, content);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Construct a ContextState from a dict, migrating old mode names.
|
|
83
|
+
* Only includes fields that are present in the source data (preserves null-stripping).
|
|
84
|
+
*/
|
|
85
|
+
export function dictToState(data: Record<string, any>): ContextState {
|
|
86
|
+
const rawMode: string = data.mode ?? "idle";
|
|
87
|
+
const mode: Mode = (MODE_MIGRATION[rawMode] ?? rawMode) as Mode;
|
|
88
|
+
|
|
89
|
+
const state: any = {
|
|
90
|
+
id: data.id,
|
|
91
|
+
status: data.status ?? "active",
|
|
92
|
+
summary: data.summary ?? "",
|
|
93
|
+
method: data.method ?? "",
|
|
94
|
+
tags: data.tags ?? [],
|
|
95
|
+
created_at: data.created_at ?? "",
|
|
96
|
+
last_active: data.last_active ?? "",
|
|
97
|
+
mode,
|
|
98
|
+
plan_anchors: data.plan_anchors ?? [],
|
|
99
|
+
plan_consumed: data.plan_consumed ?? false,
|
|
100
|
+
handoff_consumed: data.handoff_consumed ?? false,
|
|
101
|
+
session_ids: data.session_ids ?? [],
|
|
102
|
+
tasks: data.tasks ?? [],
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Only set nullable fields if they exist in the source data
|
|
106
|
+
if ("plan_path" in data) state.plan_path = data.plan_path;
|
|
107
|
+
if ("plan_hash" in data) state.plan_hash = data.plan_hash;
|
|
108
|
+
if ("plan_signature" in data) state.plan_signature = data.plan_signature;
|
|
109
|
+
if ("plan_id" in data) state.plan_id = data.plan_id;
|
|
110
|
+
if ("handoff_path" in data) state.handoff_path = data.handoff_path;
|
|
111
|
+
if ("last_session" in data) state.last_session = data.last_session;
|
|
112
|
+
|
|
113
|
+
return state as ContextState;
|
|
114
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stop words for context ID generation.
|
|
3
|
+
*
|
|
4
|
+
* Generated from analysis of 1,424 prompts, context summaries, and plan files.
|
|
5
|
+
* Words that appear frequently but don't help identify the specific task.
|
|
6
|
+
*
|
|
7
|
+
* ACTION VERBS ARE INTENTIONALLY EXCLUDED:
|
|
8
|
+
* add, fix, update, create, implement, refactor, migrate, debug, remove, change,
|
|
9
|
+
* move, rename, delete, build, test, deploy, verify, analyze, modify, write, run,
|
|
10
|
+
* check, replace, save, sync, load, extract, install, clean, merge, etc.
|
|
11
|
+
*
|
|
12
|
+
* See SPEC.md §14.1
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const STOP_WORDS: ReadonlySet<string> = new Set([
|
|
16
|
+
// ARTICLES
|
|
17
|
+
"a", "an", "the",
|
|
18
|
+
|
|
19
|
+
// PREPOSITIONS
|
|
20
|
+
"to", "for", "in", "on", "at", "by", "with", "from", "of", "about",
|
|
21
|
+
"into", "over", "under", "between", "through", "during", "before", "after",
|
|
22
|
+
"above", "below", "against", "among", "around", "behind", "beside", "besides",
|
|
23
|
+
"beyond", "down", "inside", "outside", "near", "off", "onto", "out",
|
|
24
|
+
"since", "toward", "towards", "until", "upon", "within", "without",
|
|
25
|
+
"across", "along", "via", "per",
|
|
26
|
+
|
|
27
|
+
// PRONOUNS - Personal
|
|
28
|
+
"i", "you", "he", "she", "it", "we", "they",
|
|
29
|
+
"me", "him", "her", "us", "them",
|
|
30
|
+
"myself", "yourself", "himself", "herself", "itself", "ourselves", "themselves",
|
|
31
|
+
|
|
32
|
+
// PRONOUNS - Possessive
|
|
33
|
+
"my", "your", "his", "her", "its", "our", "their",
|
|
34
|
+
"mine", "yours", "hers", "ours", "theirs",
|
|
35
|
+
|
|
36
|
+
// PRONOUNS - Demonstrative
|
|
37
|
+
"this", "that", "these", "those",
|
|
38
|
+
|
|
39
|
+
// PRONOUNS - Relative
|
|
40
|
+
"who", "whom", "whose", "which",
|
|
41
|
+
|
|
42
|
+
// PRONOUNS - Indefinite
|
|
43
|
+
"someone", "somebody", "something", "anyone", "anybody", "anything",
|
|
44
|
+
"everyone", "everybody", "everything", "no one", "nobody", "nothing",
|
|
45
|
+
"one", "ones",
|
|
46
|
+
|
|
47
|
+
// AUXILIARY/MODAL VERBS
|
|
48
|
+
"am", "is", "are", "was", "were", "be", "been", "being",
|
|
49
|
+
"have", "has", "had", "having",
|
|
50
|
+
"do", "does", "did", "doing", "done",
|
|
51
|
+
"can", "could", "will", "would", "shall", "should", "may", "might", "must",
|
|
52
|
+
|
|
53
|
+
// CONJUNCTIONS
|
|
54
|
+
"and", "or", "but", "nor", "so", "yet",
|
|
55
|
+
"if", "then", "else", "whether", "unless", "although", "though",
|
|
56
|
+
"because", "while", "whereas", "whenever", "wherever",
|
|
57
|
+
|
|
58
|
+
// QUESTION WORDS
|
|
59
|
+
"what", "when", "where", "why", "how",
|
|
60
|
+
|
|
61
|
+
// ADVERBS OF PLACE/TIME
|
|
62
|
+
"here", "there", "now", "always", "never", "often", "sometimes",
|
|
63
|
+
"already", "still", "soon", "later", "ago", "today", "tomorrow",
|
|
64
|
+
"yesterday", "currently", "previously", "recently", "immediately",
|
|
65
|
+
"finally", "eventually", "meanwhile", "afterwards",
|
|
66
|
+
|
|
67
|
+
// NEGATION
|
|
68
|
+
"no", "not", "none", "neither",
|
|
69
|
+
"don", "doesn", "didn", "won", "wouldn", "couldn", "shouldn",
|
|
70
|
+
"isn", "aren", "wasn", "weren", "hasn", "haven", "hadn",
|
|
71
|
+
|
|
72
|
+
// QUANTIFIERS
|
|
73
|
+
"some", "any", "all", "each", "every", "both", "few", "more", "most",
|
|
74
|
+
"many", "much", "several", "other", "another", "enough", "less", "least",
|
|
75
|
+
"either", "such",
|
|
76
|
+
|
|
77
|
+
// FILLER/HEDGE WORDS
|
|
78
|
+
"just", "also", "only", "really", "actually", "basically", "simply",
|
|
79
|
+
"very", "quite", "rather", "pretty", "somewhat", "almost", "nearly",
|
|
80
|
+
"exactly", "completely", "entirely", "totally", "absolutely",
|
|
81
|
+
"probably", "possibly", "maybe", "perhaps", "definitely", "certainly",
|
|
82
|
+
"apparently", "obviously", "clearly", "literally", "essentially",
|
|
83
|
+
|
|
84
|
+
// SPEECH-TO-TEXT FILLERS (STT artifacts from voice input)
|
|
85
|
+
"um", "uh", "ah", "oh", "hmm", "hm", "er", "eh", "huh",
|
|
86
|
+
"hey", "hi", "hello", "yeah", "yep", "yup", "nah", "nope",
|
|
87
|
+
"gonna", "gotta", "wanna", "kinda", "sorta",
|
|
88
|
+
"stuff", "anyway", "anyways", "alright", "right", "well",
|
|
89
|
+
|
|
90
|
+
// COMMON REQUEST PHRASES
|
|
91
|
+
"want", "need", "help", "please", "like", "let", "get",
|
|
92
|
+
"think", "know", "see", "try", "make", "give", "take",
|
|
93
|
+
"look", "looking", "trying", "going", "getting", "making",
|
|
94
|
+
|
|
95
|
+
// COMMON NON-ACTION VERBS
|
|
96
|
+
"go", "come", "put", "say", "tell", "ask", "find", "keep",
|
|
97
|
+
"seem", "appear", "become", "remain", "stay", "feel", "show", "mean",
|
|
98
|
+
"include", "provide", "require", "allow", "expect", "cause",
|
|
99
|
+
"follow", "consider", "continue", "start", "begin", "end",
|
|
100
|
+
"contain", "contains",
|
|
101
|
+
|
|
102
|
+
// LINKING/TRANSITION WORDS
|
|
103
|
+
"however", "therefore", "thus", "hence", "otherwise", "instead",
|
|
104
|
+
"moreover", "furthermore", "nevertheless", "nonetheless", "accordingly",
|
|
105
|
+
"consequently", "similarly", "likewise", "conversely", "alternatively",
|
|
106
|
+
|
|
107
|
+
// FILE EXTENSIONS
|
|
108
|
+
"py", "md", "ts", "json", "js", "yaml", "toml", "exe", "bat",
|
|
109
|
+
|
|
110
|
+
// COMMON CODING TERMS
|
|
111
|
+
"using", "used", "uses",
|
|
112
|
+
"based", "following",
|
|
113
|
+
"same", "different", "specific", "existing", "new", "current", "first",
|
|
114
|
+
"full", "complete", "single", "multiple", "simple",
|
|
115
|
+
"needed", "required", "provided", "expected", "correctly",
|
|
116
|
+
"works", "working", "work",
|
|
117
|
+
|
|
118
|
+
// STRUCTURAL WORDS
|
|
119
|
+
"step", "steps", "phase", "below",
|
|
120
|
+
|
|
121
|
+
// QUERY LANGUAGE
|
|
122
|
+
"questions", "question", "clarification",
|
|
123
|
+
|
|
124
|
+
// OVERLY GENERIC TERMS
|
|
125
|
+
"thing", "things", "way", "ways", "kind", "type", "types",
|
|
126
|
+
"example", "examples", "case", "cases",
|
|
127
|
+
"part", "parts", "point", "points",
|
|
128
|
+
"time", "times", "next", "last",
|
|
129
|
+
"set", "list", "group", "item", "items",
|
|
130
|
+
|
|
131
|
+
// PROGRAMMING KEYWORDS
|
|
132
|
+
"self", "def", "return", "import", "true", "false", "none", "str",
|
|
133
|
+
"const", "async", "class", "assert", "except", "dict", "len", "args",
|
|
134
|
+
"sys", "eprint", "elif", "lambda", "yield", "pass",
|
|
135
|
+
|
|
136
|
+
// GENERIC ADJECTIVES
|
|
137
|
+
"high", "low", "important", "critical", "optional", "manual",
|
|
138
|
+
"real", "empty", "stable", "active", "proper", "correct",
|
|
139
|
+
"basic", "main", "primary", "secondary", "general", "overall",
|
|
140
|
+
|
|
141
|
+
// GENERIC TECHNICAL NOUNS
|
|
142
|
+
"information", "format", "status", "method", "purpose", "result",
|
|
143
|
+
"source", "value", "option", "options", "feature", "features", "issue",
|
|
144
|
+
"process", "version", "mode", "state",
|
|
145
|
+
|
|
146
|
+
// DOCUMENT/CODE STRUCTURE
|
|
147
|
+
"section", "lines", "line", "folder", "directory", "index",
|
|
148
|
+
"level", "block", "chunk", "region", "header", "footer",
|
|
149
|
+
|
|
150
|
+
// FRAGMENT WORDS
|
|
151
|
+
"re", "pl", "aiw", "ve", "ll", "doesn", "t", "s",
|
|
152
|
+
|
|
153
|
+
// CONTRACTED FORMS
|
|
154
|
+
"im", "ive", "id", "ill", "youre", "youve", "youll",
|
|
155
|
+
"hes", "shes", "weve", "theyre", "theyve", "dont", "doesnt",
|
|
156
|
+
"didnt", "wont", "wouldnt", "cant", "couldnt", "shouldnt", "isnt",
|
|
157
|
+
"arent", "wasnt", "werent", "hasnt", "havent", "hadnt", "lets",
|
|
158
|
+
"thats", "whats", "heres", "theres", "whos",
|
|
159
|
+
|
|
160
|
+
// SHORT NOISE
|
|
161
|
+
"etc", "up", "as", "cc",
|
|
162
|
+
|
|
163
|
+
// NUMBER WORDS
|
|
164
|
+
"two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
|
|
165
|
+
|
|
166
|
+
// SINGLE LETTERS
|
|
167
|
+
"b", "c", "d", "e", "f", "g", "h", "j", "k", "l", "m", "n", "o", "p",
|
|
168
|
+
"q", "r", "u", "v", "w", "x", "y", "z",
|
|
169
|
+
|
|
170
|
+
// SHORT FILLER
|
|
171
|
+
"too", "yes", "ok", "okay",
|
|
172
|
+
]);
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Filter stop words from text.
|
|
176
|
+
* Splits on whitespace, removes words in STOP_WORDS set and single-char words.
|
|
177
|
+
* See SPEC.md §6.4
|
|
178
|
+
*/
|
|
179
|
+
export function filterStopWords(text: string): string {
|
|
180
|
+
return text
|
|
181
|
+
.split(/\s+/)
|
|
182
|
+
.filter((word) => word.length > 1 && !STOP_WORDS.has(word.toLowerCase()))
|
|
183
|
+
.join(" ");
|
|
184
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subprocess environment utilities.
|
|
3
|
+
* See SPEC.md §5.10
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check if this is an internal subprocess call.
|
|
8
|
+
* All hooks should check this and return early to prevent recursion.
|
|
9
|
+
*/
|
|
10
|
+
export function isInternalCall(): boolean {
|
|
11
|
+
return process.env.AIWCLI_INTERNAL_CALL === "true";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get environment for internal subprocess calls.
|
|
16
|
+
* Returns a copy of process.env with AIWCLI_INTERNAL_CALL=true.
|
|
17
|
+
*/
|
|
18
|
+
export function getInternalSubprocessEnv(): Record<string, string | undefined> {
|
|
19
|
+
return {
|
|
20
|
+
...process.env,
|
|
21
|
+
AIWCLI_INTERNAL_CALL: "true",
|
|
22
|
+
};
|
|
23
|
+
}
|