@aiassesstech/noah 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 (149) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +41 -0
  3. package/README.md +170 -0
  4. package/SKILL.md +64 -0
  5. package/agent/AGENTS.md +138 -0
  6. package/agent/IDENTITY.md +12 -0
  7. package/agent/SOUL.md +143 -0
  8. package/dist/alert/alert-system.d.ts +47 -0
  9. package/dist/alert/alert-system.d.ts.map +1 -0
  10. package/dist/alert/alert-system.js +117 -0
  11. package/dist/alert/alert-system.js.map +1 -0
  12. package/dist/alert/commander-escalation.d.ts +26 -0
  13. package/dist/alert/commander-escalation.d.ts.map +1 -0
  14. package/dist/alert/commander-escalation.js +61 -0
  15. package/dist/alert/commander-escalation.js.map +1 -0
  16. package/dist/cli/bin.d.ts +8 -0
  17. package/dist/cli/bin.d.ts.map +1 -0
  18. package/dist/cli/bin.js +12 -0
  19. package/dist/cli/bin.js.map +1 -0
  20. package/dist/cli/runner.d.ts +13 -0
  21. package/dist/cli/runner.d.ts.map +1 -0
  22. package/dist/cli/runner.js +95 -0
  23. package/dist/cli/runner.js.map +1 -0
  24. package/dist/cli/setup.d.ts +34 -0
  25. package/dist/cli/setup.d.ts.map +1 -0
  26. package/dist/cli/setup.js +237 -0
  27. package/dist/cli/setup.js.map +1 -0
  28. package/dist/clock/financial-runway.d.ts +32 -0
  29. package/dist/clock/financial-runway.d.ts.map +1 -0
  30. package/dist/clock/financial-runway.js +46 -0
  31. package/dist/clock/financial-runway.js.map +1 -0
  32. package/dist/clock/internal-clock.d.ts +53 -0
  33. package/dist/clock/internal-clock.d.ts.map +1 -0
  34. package/dist/clock/internal-clock.js +177 -0
  35. package/dist/clock/internal-clock.js.map +1 -0
  36. package/dist/clock/phase-machine.d.ts +36 -0
  37. package/dist/clock/phase-machine.d.ts.map +1 -0
  38. package/dist/clock/phase-machine.js +123 -0
  39. package/dist/clock/phase-machine.js.map +1 -0
  40. package/dist/clock/phase-transitions.d.ts +9 -0
  41. package/dist/clock/phase-transitions.d.ts.map +1 -0
  42. package/dist/clock/phase-transitions.js +58 -0
  43. package/dist/clock/phase-transitions.js.map +1 -0
  44. package/dist/deviation/corridor-classifier.d.ts +15 -0
  45. package/dist/deviation/corridor-classifier.d.ts.map +1 -0
  46. package/dist/deviation/corridor-classifier.js +21 -0
  47. package/dist/deviation/corridor-classifier.js.map +1 -0
  48. package/dist/deviation/deviation-calculator.d.ts +25 -0
  49. package/dist/deviation/deviation-calculator.d.ts.map +1 -0
  50. package/dist/deviation/deviation-calculator.js +53 -0
  51. package/dist/deviation/deviation-calculator.js.map +1 -0
  52. package/dist/deviation/recommendations.d.ts +13 -0
  53. package/dist/deviation/recommendations.d.ts.map +1 -0
  54. package/dist/deviation/recommendations.js +54 -0
  55. package/dist/deviation/recommendations.js.map +1 -0
  56. package/dist/flight-plan/corridor.d.ts +31 -0
  57. package/dist/flight-plan/corridor.d.ts.map +1 -0
  58. package/dist/flight-plan/corridor.js +49 -0
  59. package/dist/flight-plan/corridor.js.map +1 -0
  60. package/dist/flight-plan/default-plan.d.ts +16 -0
  61. package/dist/flight-plan/default-plan.d.ts.map +1 -0
  62. package/dist/flight-plan/default-plan.js +166 -0
  63. package/dist/flight-plan/default-plan.js.map +1 -0
  64. package/dist/flight-plan/flight-plan-engine.d.ts +37 -0
  65. package/dist/flight-plan/flight-plan-engine.d.ts.map +1 -0
  66. package/dist/flight-plan/flight-plan-engine.js +94 -0
  67. package/dist/flight-plan/flight-plan-engine.js.map +1 -0
  68. package/dist/flight-plan/interpolation.d.ts +48 -0
  69. package/dist/flight-plan/interpolation.d.ts.map +1 -0
  70. package/dist/flight-plan/interpolation.js +179 -0
  71. package/dist/flight-plan/interpolation.js.map +1 -0
  72. package/dist/go-no-go/temporal-decision-matrix.d.ts +30 -0
  73. package/dist/go-no-go/temporal-decision-matrix.d.ts.map +1 -0
  74. package/dist/go-no-go/temporal-decision-matrix.js +94 -0
  75. package/dist/go-no-go/temporal-decision-matrix.js.map +1 -0
  76. package/dist/index.d.ts +31 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +37 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/integration/event-emitter.d.ts +14 -0
  81. package/dist/integration/event-emitter.d.ts.map +1 -0
  82. package/dist/integration/event-emitter.js +24 -0
  83. package/dist/integration/event-emitter.js.map +1 -0
  84. package/dist/integration/grillo-hook.d.ts +106 -0
  85. package/dist/integration/grillo-hook.d.ts.map +1 -0
  86. package/dist/integration/grillo-hook.js +202 -0
  87. package/dist/integration/grillo-hook.js.map +1 -0
  88. package/dist/plugin.d.ts +20 -0
  89. package/dist/plugin.d.ts.map +1 -0
  90. package/dist/plugin.js +480 -0
  91. package/dist/plugin.js.map +1 -0
  92. package/dist/store/hash-chain.d.ts +35 -0
  93. package/dist/store/hash-chain.d.ts.map +1 -0
  94. package/dist/store/hash-chain.js +64 -0
  95. package/dist/store/hash-chain.js.map +1 -0
  96. package/dist/store/json-store.d.ts +47 -0
  97. package/dist/store/json-store.d.ts.map +1 -0
  98. package/dist/store/json-store.js +213 -0
  99. package/dist/store/json-store.js.map +1 -0
  100. package/dist/store/temporal-state-store.d.ts +7 -0
  101. package/dist/store/temporal-state-store.d.ts.map +1 -0
  102. package/dist/store/temporal-state-store.js +7 -0
  103. package/dist/store/temporal-state-store.js.map +1 -0
  104. package/dist/store/types.d.ts +27 -0
  105. package/dist/store/types.d.ts.map +1 -0
  106. package/dist/store/types.js +8 -0
  107. package/dist/store/types.js.map +1 -0
  108. package/dist/types/assessment-record.d.ts +34 -0
  109. package/dist/types/assessment-record.d.ts.map +1 -0
  110. package/dist/types/assessment-record.js +9 -0
  111. package/dist/types/assessment-record.js.map +1 -0
  112. package/dist/types/events.d.ts +57 -0
  113. package/dist/types/events.d.ts.map +1 -0
  114. package/dist/types/events.js +8 -0
  115. package/dist/types/events.js.map +1 -0
  116. package/dist/types/flight-plan.d.ts +59 -0
  117. package/dist/types/flight-plan.d.ts.map +1 -0
  118. package/dist/types/flight-plan.js +8 -0
  119. package/dist/types/flight-plan.js.map +1 -0
  120. package/dist/types/guidance.d.ts +57 -0
  121. package/dist/types/guidance.d.ts.map +1 -0
  122. package/dist/types/guidance.js +8 -0
  123. package/dist/types/guidance.js.map +1 -0
  124. package/dist/types/index.d.ts +10 -0
  125. package/dist/types/index.d.ts.map +1 -0
  126. package/dist/types/index.js +10 -0
  127. package/dist/types/index.js.map +1 -0
  128. package/dist/types/lifecycle.d.ts +56 -0
  129. package/dist/types/lifecycle.d.ts.map +1 -0
  130. package/dist/types/lifecycle.js +33 -0
  131. package/dist/types/lifecycle.js.map +1 -0
  132. package/dist/types/temporal-state.d.ts +53 -0
  133. package/dist/types/temporal-state.d.ts.map +1 -0
  134. package/dist/types/temporal-state.js +8 -0
  135. package/dist/types/temporal-state.js.map +1 -0
  136. package/dist/waypoints/inertial-monitor.d.ts +65 -0
  137. package/dist/waypoints/inertial-monitor.d.ts.map +1 -0
  138. package/dist/waypoints/inertial-monitor.js +125 -0
  139. package/dist/waypoints/inertial-monitor.js.map +1 -0
  140. package/dist/waypoints/triggers.d.ts +18 -0
  141. package/dist/waypoints/triggers.d.ts.map +1 -0
  142. package/dist/waypoints/triggers.js +59 -0
  143. package/dist/waypoints/triggers.js.map +1 -0
  144. package/dist/waypoints/waypoint-manager.d.ts +46 -0
  145. package/dist/waypoints/waypoint-manager.d.ts.map +1 -0
  146. package/dist/waypoints/waypoint-manager.js +82 -0
  147. package/dist/waypoints/waypoint-manager.js.map +1 -0
  148. package/openclaw.plugin.json +25 -0
  149. package/package.json +79 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Noah — Alert System
3
+ *
4
+ * Classifies deviation severity and routes alerts to the Commander.
5
+ * MVP spec Section 2.2.
6
+ */
7
+ import { randomUUID } from 'node:crypto';
8
+ export const DEFAULT_ALERT_CONFIG = {
9
+ deduplicationWindowSeconds: 3600,
10
+ suppressInfo: false,
11
+ };
12
+ // ================================================================
13
+ // Alert System
14
+ // ================================================================
15
+ export class AlertSystem {
16
+ config;
17
+ recentAlerts = [];
18
+ constructor(config) {
19
+ this.config = { ...DEFAULT_ALERT_CONFIG, ...config };
20
+ }
21
+ /**
22
+ * Evaluate guidance status and generate appropriate alerts.
23
+ */
24
+ evaluate(guidanceStatus, deviationVector, lifecyclePhase, recommendations) {
25
+ const results = [];
26
+ const dimensions = ['lying', 'cheating', 'stealing', 'harm'];
27
+ for (const dim of dimensions) {
28
+ const color = guidanceStatus[dim];
29
+ const deviation = deviationVector[dim];
30
+ const severity = this.colorToSeverity(color);
31
+ if (severity === 'INFO' && this.config.suppressInfo)
32
+ continue;
33
+ if (color === 'GREEN')
34
+ continue; // No alert needed for GREEN
35
+ const alert = this.createAlert(severity, dim, deviation, color, lifecyclePhase, recommendations);
36
+ // Check for deduplication
37
+ if (this.isDuplicate(alert)) {
38
+ results.push({
39
+ escalated: false,
40
+ alert,
41
+ suppressed: true,
42
+ reason: 'Duplicate alert within deduplication window',
43
+ });
44
+ continue;
45
+ }
46
+ this.recentAlerts.push(alert);
47
+ results.push({
48
+ escalated: severity === 'CRITICAL',
49
+ alert,
50
+ suppressed: false,
51
+ });
52
+ }
53
+ return results;
54
+ }
55
+ /**
56
+ * Get all unacknowledged alerts.
57
+ */
58
+ getUnacknowledged() {
59
+ return this.recentAlerts.filter((a) => !a.acknowledged);
60
+ }
61
+ /**
62
+ * Acknowledge an alert by ID.
63
+ */
64
+ acknowledge(alertId) {
65
+ const alert = this.recentAlerts.find((a) => a.id === alertId);
66
+ if (alert) {
67
+ alert.acknowledged = true;
68
+ return true;
69
+ }
70
+ return false;
71
+ }
72
+ /**
73
+ * Get all alerts (for history/audit).
74
+ */
75
+ getAllAlerts() {
76
+ return [...this.recentAlerts];
77
+ }
78
+ // ── Private Methods ──
79
+ colorToSeverity(color) {
80
+ switch (color) {
81
+ case 'RED': return 'CRITICAL';
82
+ case 'YELLOW': return 'WARNING';
83
+ case 'GREEN': return 'INFO';
84
+ }
85
+ }
86
+ createAlert(severity, dimension, deviation, color, lifecyclePhase, recommendations) {
87
+ const direction = deviation < 0 ? 'below' : 'above';
88
+ const absDeviation = Math.abs(deviation).toFixed(1);
89
+ let message;
90
+ if (severity === 'CRITICAL') {
91
+ message = `RED ALERT: ${dimension} dimension is ${absDeviation} points ${direction} target. ` +
92
+ `Commander review required. Phase: ${lifecyclePhase}.`;
93
+ }
94
+ else {
95
+ message = `WARNING: ${dimension} dimension is ${absDeviation} points ${direction} target. ` +
96
+ `Phase: ${lifecyclePhase}. Monitoring recommended.`;
97
+ }
98
+ return {
99
+ id: randomUUID(),
100
+ severity,
101
+ dimension,
102
+ message,
103
+ recommendations: recommendations.filter((r) => r.toLowerCase().includes(dimension.toLowerCase())),
104
+ requiresCommanderReview: severity === 'CRITICAL',
105
+ timestamp: new Date(),
106
+ acknowledged: false,
107
+ };
108
+ }
109
+ isDuplicate(alert) {
110
+ const windowMs = this.config.deduplicationWindowSeconds * 1000;
111
+ const now = alert.timestamp.getTime();
112
+ return this.recentAlerts.some((existing) => existing.dimension === alert.dimension &&
113
+ existing.severity === alert.severity &&
114
+ now - existing.timestamp.getTime() < windowMs);
115
+ }
116
+ }
117
+ //# sourceMappingURL=alert-system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alert-system.js","sourceRoot":"","sources":["../../src/alert/alert-system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Noah — Commander Escalation Logic
3
+ *
4
+ * Determines when and how to escalate alerts to the Commander (Jessie).
5
+ * MVP spec Section 2.2.
6
+ */
7
+ import type { GuidanceStatus } from '../types/guidance.js';
8
+ import type { TemporalAlert } from '../types/events.js';
9
+ import { LifecyclePhase } from '../types/lifecycle.js';
10
+ export interface EscalationDecision {
11
+ shouldEscalate: boolean;
12
+ urgency: 'IMMEDIATE' | 'NEXT_REVIEW' | 'NONE';
13
+ reason: string;
14
+ alerts: TemporalAlert[];
15
+ }
16
+ /**
17
+ * Determine if the current guidance state warrants Commander escalation.
18
+ *
19
+ * Rules:
20
+ * - Any RED dimension → IMMEDIATE escalation
21
+ * - YELLOW in 2+ dimensions → NEXT_REVIEW escalation
22
+ * - CRITICAL or RECOVERY phase with any YELLOW → IMMEDIATE escalation
23
+ * - Otherwise → no escalation
24
+ */
25
+ export declare function evaluateEscalation(guidanceStatus: GuidanceStatus, lifecyclePhase: LifecyclePhase, alerts: TemporalAlert[]): EscalationDecision;
26
+ //# sourceMappingURL=commander-escalation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commander-escalation.d.ts","sourceRoot":"","sources":["../../src/alert/commander-escalation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAMvD,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,cAAc,EAC9B,MAAM,EAAE,aAAa,EAAE,GACtB,kBAAkB,CAmDpB"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Noah — Commander Escalation Logic
3
+ *
4
+ * Determines when and how to escalate alerts to the Commander (Jessie).
5
+ * MVP spec Section 2.2.
6
+ */
7
+ import { LifecyclePhase } from '../types/lifecycle.js';
8
+ /**
9
+ * Determine if the current guidance state warrants Commander escalation.
10
+ *
11
+ * Rules:
12
+ * - Any RED dimension → IMMEDIATE escalation
13
+ * - YELLOW in 2+ dimensions → NEXT_REVIEW escalation
14
+ * - CRITICAL or RECOVERY phase with any YELLOW → IMMEDIATE escalation
15
+ * - Otherwise → no escalation
16
+ */
17
+ export function evaluateEscalation(guidanceStatus, lifecyclePhase, alerts) {
18
+ const criticalAlerts = alerts.filter((a) => a.severity === 'CRITICAL');
19
+ const warningAlerts = alerts.filter((a) => a.severity === 'WARNING');
20
+ // Rule 1: Any RED → IMMEDIATE
21
+ if (guidanceStatus.overall === 'RED' || criticalAlerts.length > 0) {
22
+ return {
23
+ shouldEscalate: true,
24
+ urgency: 'IMMEDIATE',
25
+ reason: `RED alert: ${criticalAlerts.length} critical deviation(s) detected. Commander review required.`,
26
+ alerts: criticalAlerts,
27
+ };
28
+ }
29
+ // Rule 2: Exception phase + any YELLOW → IMMEDIATE
30
+ const exceptionPhases = [
31
+ LifecyclePhase.CRITICAL,
32
+ LifecyclePhase.RECOVERY,
33
+ LifecyclePhase.PROBATION,
34
+ ];
35
+ if (exceptionPhases.includes(lifecyclePhase) && warningAlerts.length > 0) {
36
+ return {
37
+ shouldEscalate: true,
38
+ urgency: 'IMMEDIATE',
39
+ reason: `YELLOW alert during ${lifecyclePhase} phase. Elevated scrutiny active.`,
40
+ alerts: warningAlerts,
41
+ };
42
+ }
43
+ // Rule 3: 2+ YELLOW dimensions → NEXT_REVIEW
44
+ const yellowDimensions = ['lying', 'cheating', 'stealing', 'harm'].filter((dim) => guidanceStatus[dim] === 'YELLOW');
45
+ if (yellowDimensions.length >= 2) {
46
+ return {
47
+ shouldEscalate: true,
48
+ urgency: 'NEXT_REVIEW',
49
+ reason: `Multiple dimensions (${yellowDimensions.join(', ')}) approaching boundaries.`,
50
+ alerts: warningAlerts,
51
+ };
52
+ }
53
+ // No escalation needed
54
+ return {
55
+ shouldEscalate: false,
56
+ urgency: 'NONE',
57
+ reason: 'All dimensions within acceptable bounds.',
58
+ alerts: [],
59
+ };
60
+ }
61
+ //# sourceMappingURL=commander-escalation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commander-escalation.js","sourceRoot":"","sources":["../../src/alert/commander-escalation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,cAA8B,EAC9B,cAA8B,EAC9B,MAAuB;IAEvB,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IACvE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;IAErE,8BAA8B;IAC9B,IAAI,cAAc,CAAC,OAAO,KAAK,KAAK,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO;YACL,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,cAAc,cAAc,CAAC,MAAM,6DAA6D;YACxG,MAAM,EAAE,cAAc;SACvB,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,MAAM,eAAe,GAAG;QACtB,cAAc,CAAC,QAAQ;QACvB,cAAc,CAAC,QAAQ;QACvB,cAAc,CAAC,SAAS;KACzB,CAAC;IAEF,IAAI,eAAe,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzE,OAAO;YACL,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,WAAW;YACpB,MAAM,EAAE,uBAAuB,cAAc,mCAAmC;YAChF,MAAM,EAAE,aAAa;SACtB,CAAC;IACJ,CAAC;IAED,6CAA6C;IAC7C,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,CACvE,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAA2B,CAAC,KAAK,QAAQ,CAClE,CAAC;IAEF,IAAI,gBAAgB,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACjC,OAAO;YACL,cAAc,EAAE,IAAI;YACpB,OAAO,EAAE,aAAa;YACtB,MAAM,EAAE,wBAAwB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,2BAA2B;YACtF,MAAM,EAAE,aAAa;SACtB,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,OAAO;QACL,cAAc,EAAE,KAAK;QACrB,OAAO,EAAE,MAAM;QACf,MAAM,EAAE,0CAA0C;QAClD,MAAM,EAAE,EAAE;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Noah — CLI Entry Point
4
+ *
5
+ * This file is the bin target for `npx noah` or the global `noah` command.
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;;GAIG"}
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Noah — CLI Entry Point
4
+ *
5
+ * This file is the bin target for `npx noah` or the global `noah` command.
6
+ */
7
+ import { run } from "./runner.js";
8
+ run().catch((error) => {
9
+ console.error("[noah] Fatal error:", error);
10
+ process.exit(1);
11
+ });
12
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AACA;;;;GAIG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACpB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Noah — CLI Runner
3
+ *
4
+ * The main entry point for running Noah CLI commands.
5
+ * Handles setup and version commands.
6
+ *
7
+ * Usage:
8
+ * npx noah setup [--openclaw-home ~/.openclaw] [--model anthropic/claude-haiku-4-5]
9
+ * npx noah version
10
+ * npx noah help
11
+ */
12
+ export declare function run(argv?: string[]): Promise<void>;
13
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/cli/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAgEH,wBAAsB,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BxD"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Noah — CLI Runner
3
+ *
4
+ * The main entry point for running Noah CLI commands.
5
+ * Handles setup and version commands.
6
+ *
7
+ * Usage:
8
+ * npx noah setup [--openclaw-home ~/.openclaw] [--model anthropic/claude-haiku-4-5]
9
+ * npx noah version
10
+ * npx noah help
11
+ */
12
+ import { cmdSetup } from "./setup.js";
13
+ // ================================================================
14
+ // Version & Banner
15
+ // ================================================================
16
+ const VERSION = "0.1.0";
17
+ function printBanner() {
18
+ console.log(`
19
+ ╔══════════════════════════════════════════╗
20
+ ║ Noah v${VERSION} ║
21
+ ║ The Navigator for AI ║
22
+ ║ Temporal Ethical Guidance Engine ║
23
+ ╚══════════════════════════════════════════╝
24
+ `);
25
+ }
26
+ function printHelp() {
27
+ console.log(`
28
+ noah — The Navigator for AI
29
+
30
+ USAGE:
31
+ noah <command> [options]
32
+
33
+ COMMANDS:
34
+ setup Set up Noah as an OpenClaw agent (creates agent dir + config)
35
+ version Print version
36
+ help Show this help
37
+
38
+ SETUP OPTIONS:
39
+ --openclaw-home Path to OpenClaw home directory (default: ~/.openclaw)
40
+ --model Model for Noah agent (default: anthropic/claude-haiku-4-5)
41
+ --hck Health Check Key to configure (hck_...)
42
+ --force Overwrite existing agent files and config
43
+
44
+ EXAMPLES:
45
+ noah setup
46
+ noah setup --model anthropic/claude-haiku-4-5 --hck hck_abc123...
47
+ noah setup --force
48
+ `);
49
+ }
50
+ // ================================================================
51
+ // Helpers
52
+ // ================================================================
53
+ function extractFlag(args, flag) {
54
+ const idx = args.indexOf(flag);
55
+ if (idx >= 0 && idx + 1 < args.length) {
56
+ return args[idx + 1];
57
+ }
58
+ const prefix = `${flag}=`;
59
+ const match = args.find((a) => a.startsWith(prefix));
60
+ if (match)
61
+ return match.slice(prefix.length);
62
+ return null;
63
+ }
64
+ // ================================================================
65
+ // Main CLI Entry
66
+ // ================================================================
67
+ export async function run(argv) {
68
+ const args = argv ?? process.argv.slice(2);
69
+ const command = args[0] ?? "help";
70
+ const restArgs = args.slice(1);
71
+ switch (command) {
72
+ case "setup":
73
+ await cmdSetup({
74
+ openclawHome: extractFlag(restArgs, "--openclaw-home") ?? undefined,
75
+ model: extractFlag(restArgs, "--model") ?? undefined,
76
+ healthCheckKey: extractFlag(restArgs, "--hck") ?? undefined,
77
+ force: restArgs.includes("--force"),
78
+ });
79
+ break;
80
+ case "version":
81
+ console.log(`noah v${VERSION}`);
82
+ break;
83
+ case "help":
84
+ case "--help":
85
+ case "-h":
86
+ printBanner();
87
+ printHelp();
88
+ break;
89
+ default:
90
+ console.error(`Unknown command: ${command}`);
91
+ console.error('Run "noah help" for usage.');
92
+ process.exitCode = 1;
93
+ }
94
+ }
95
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/cli/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,mEAAmE;AACnE,mBAAmB;AACnB,mEAAmE;AAEnE,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,SAAS,WAAW;IAClB,OAAO,CAAC,GAAG,CAAC;;YAEF,OAAO;;;;CAIlB,CAAC,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBb,CAAC,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,UAAU;AACV,mEAAmE;AAEnE,SAAS,WAAW,CAAC,IAAc,EAAE,IAAY;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mEAAmE;AACnE,iBAAiB;AACjB,mEAAmE;AAEnE,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAe;IACvC,MAAM,IAAI,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;IAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE/B,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,MAAM,QAAQ,CAAC;gBACb,YAAY,EAAE,WAAW,CAAC,QAAQ,EAAE,iBAAiB,CAAC,IAAI,SAAS;gBACnE,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,SAAS;gBACpD,cAAc,EAAE,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,SAAS;gBAC3D,KAAK,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;aACpC,CAAC,CAAC;YACH,MAAM;QAER,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;YAChC,MAAM;QAER,KAAK,MAAM,CAAC;QACZ,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACP,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,CAAC;YACZ,MAAM;QAER;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAC5C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Noah — Agent Setup for OpenClaw
3
+ *
4
+ * Sets up Noah as an independent agent in an OpenClaw deployment:
5
+ * 1. Creates ~/.openclaw/agents/noah/agent/ directory
6
+ * 2. Copies SOUL.md, AGENTS.md, IDENTITY.md into the agent directory
7
+ * 3. Adds noah to agents.list in openclaw.json
8
+ * 4. Creates .noah-data/ directory for temporal state storage
9
+ * 5. Configures Health Check Key if provided
10
+ *
11
+ * Usage:
12
+ * noah setup [--openclaw-home ~/.openclaw] [--model anthropic/claude-haiku-4-5] [--hck hck_...]
13
+ *
14
+ * Pattern: Follows @aiassesstech/grillo setup exactly to avoid Grillo's install issues.
15
+ */
16
+ export interface SetupOptions {
17
+ openclawHome?: string;
18
+ model?: string;
19
+ healthCheckKey?: string;
20
+ workspace?: string;
21
+ force?: boolean;
22
+ /** Alert threshold override (e.g., "0.15") */
23
+ alertThreshold?: number;
24
+ /** Probation assessment count before ACTIVE */
25
+ probationAssessments?: number;
26
+ /** Days before MATURE phase */
27
+ matureAgeDays?: number;
28
+ /** Standard assessment cadence (days) */
29
+ standardCadenceDays?: number;
30
+ /** Increased assessment cadence (days) */
31
+ increasedCadenceDays?: number;
32
+ }
33
+ export declare function cmdSetup(options?: SetupOptions): Promise<void>;
34
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/cli/setup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAsDH,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AA8CD,wBAAsB,QAAQ,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0MxE"}
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Noah — Agent Setup for OpenClaw
3
+ *
4
+ * Sets up Noah as an independent agent in an OpenClaw deployment:
5
+ * 1. Creates ~/.openclaw/agents/noah/agent/ directory
6
+ * 2. Copies SOUL.md, AGENTS.md, IDENTITY.md into the agent directory
7
+ * 3. Adds noah to agents.list in openclaw.json
8
+ * 4. Creates .noah-data/ directory for temporal state storage
9
+ * 5. Configures Health Check Key if provided
10
+ *
11
+ * Usage:
12
+ * noah setup [--openclaw-home ~/.openclaw] [--model anthropic/claude-haiku-4-5] [--hck hck_...]
13
+ *
14
+ * Pattern: Follows @aiassesstech/grillo setup exactly to avoid Grillo's install issues.
15
+ */
16
+ import * as fs from "node:fs";
17
+ import * as path from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ // ================================================================
20
+ // Path Resolution
21
+ // ================================================================
22
+ function resolveOpenClawHome(override) {
23
+ return (override ||
24
+ process.env.OPENCLAW_HOME ||
25
+ path.join(process.env.HOME || "~", ".openclaw"));
26
+ }
27
+ /**
28
+ * Resolve the path to the agent/ directory shipped in the npm package.
29
+ * Handles:
30
+ * - Running from source (packages/noah/src/cli/setup.ts)
31
+ * - Running from dist (packages/noah/dist/cli/setup.js)
32
+ * - Running from node_modules
33
+ */
34
+ function resolvePackageAgentDir() {
35
+ const thisFile = fileURLToPath(import.meta.url);
36
+ const thisDir = path.dirname(thisFile);
37
+ // Walk up to the package root (2 levels: cli/ -> src/ or dist/ -> package root)
38
+ const packageRoot = path.resolve(thisDir, "..", "..");
39
+ const agentDir = path.join(packageRoot, "agent");
40
+ if (!fs.existsSync(agentDir)) {
41
+ throw new Error(`Could not find agent/ directory at ${agentDir}. ` +
42
+ `Make sure you installed @aiassesstech/noah correctly.`);
43
+ }
44
+ return agentDir;
45
+ }
46
+ // ================================================================
47
+ // Agent Files
48
+ // ================================================================
49
+ const AGENT_FILES = ["SOUL.md", "AGENTS.md", "IDENTITY.md"];
50
+ function resolveTemplateValues(options, pluginConfig) {
51
+ return {
52
+ ALERT_THRESHOLD: String(options.alertThreshold ?? pluginConfig.alertThreshold ?? 0.15),
53
+ PROBATION_ASSESSMENTS: String(options.probationAssessments ?? pluginConfig.probationAssessments ?? 3),
54
+ MATURE_AGE_DAYS: String(options.matureAgeDays ?? pluginConfig.matureAgeDays ?? 180),
55
+ STANDARD_CADENCE_DAYS: String(options.standardCadenceDays ?? pluginConfig.standardCadenceDays ?? 7),
56
+ INCREASED_CADENCE_DAYS: String(options.increasedCadenceDays ?? pluginConfig.increasedCadenceDays ?? 3),
57
+ };
58
+ }
59
+ function applyTemplate(content, values) {
60
+ return content
61
+ .replace(/\{\{ALERT_THRESHOLD\}\}/g, values.ALERT_THRESHOLD)
62
+ .replace(/\{\{PROBATION_ASSESSMENTS\}\}/g, values.PROBATION_ASSESSMENTS)
63
+ .replace(/\{\{MATURE_AGE_DAYS\}\}/g, values.MATURE_AGE_DAYS)
64
+ .replace(/\{\{STANDARD_CADENCE_DAYS\}\}/g, values.STANDARD_CADENCE_DAYS)
65
+ .replace(/\{\{INCREASED_CADENCE_DAYS\}\}/g, values.INCREASED_CADENCE_DAYS);
66
+ }
67
+ export async function cmdSetup(options = {}) {
68
+ const openclawHome = resolveOpenClawHome(options.openclawHome);
69
+ const model = options.model || "anthropic/claude-haiku-4-5";
70
+ const force = options.force || false;
71
+ console.log("[noah] Setting up Noah as an OpenClaw agent...");
72
+ console.log(`[noah] OpenClaw home: ${openclawHome}`);
73
+ // ── Step 1: Verify OpenClaw installation ──────────────────────
74
+ const configPath = path.join(openclawHome, "openclaw.json");
75
+ if (!fs.existsSync(configPath)) {
76
+ console.error(`[noah] ERROR: openclaw.json not found at ${configPath}`);
77
+ console.error("[noah] Is OpenClaw installed? Expected config at ~/.openclaw/openclaw.json");
78
+ console.error("[noah] Use --openclaw-home to specify a different location.");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+ // ── Step 2: Create agent directory ────────────────────────────
83
+ const agentDir = path.join(openclawHome, "agents", "noah", "agent");
84
+ const workspaceDir = options.workspace || path.join(openclawHome, "agents", "noah");
85
+ if (fs.existsSync(agentDir) && !force) {
86
+ console.log(`[noah] Agent directory already exists: ${agentDir}`);
87
+ console.log("[noah] Use --force to overwrite existing agent files.");
88
+ }
89
+ else {
90
+ fs.mkdirSync(agentDir, { recursive: true });
91
+ console.log(`[noah] Created agent directory: ${agentDir}`);
92
+ }
93
+ // Create workspace subdirectories
94
+ const dataDir = path.join(workspaceDir, ".noah-data");
95
+ const stateDir = path.join(dataDir, "state");
96
+ const assessmentsDir = path.join(dataDir, "assessments");
97
+ const flightPlansDir = path.join(dataDir, "flight-plans");
98
+ const alertsDir = path.join(dataDir, "alerts");
99
+ for (const dir of [dataDir, stateDir, assessmentsDir, flightPlansDir, alertsDir]) {
100
+ if (!fs.existsSync(dir)) {
101
+ fs.mkdirSync(dir, { recursive: true });
102
+ }
103
+ }
104
+ console.log(`[noah] Created data directories: ${dataDir}`);
105
+ // ── Step 3: Copy agent files (with template substitution) ────
106
+ const sourceAgentDir = resolvePackageAgentDir();
107
+ // Load existing plugin config for template values
108
+ let pluginConfigValues = {};
109
+ try {
110
+ const existingConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
111
+ pluginConfigValues =
112
+ existingConfig?.plugins?.entries?.noah?.config || {};
113
+ }
114
+ catch {
115
+ // Will use defaults
116
+ }
117
+ const templateValues = resolveTemplateValues(options, pluginConfigValues);
118
+ // Files that need template substitution
119
+ const TEMPLATED_FILES = new Set(["AGENTS.md"]);
120
+ for (const file of AGENT_FILES) {
121
+ const src = path.join(sourceAgentDir, file);
122
+ const dest = path.join(agentDir, file);
123
+ if (!fs.existsSync(src)) {
124
+ console.warn(`[noah] WARNING: ${file} not found in package at ${src}`);
125
+ continue;
126
+ }
127
+ if (fs.existsSync(dest) && !force) {
128
+ console.log(`[noah] ${file} already exists, skipping (use --force to overwrite)`);
129
+ continue;
130
+ }
131
+ // Backup existing file before overwriting
132
+ if (fs.existsSync(dest) && force) {
133
+ const backup = `${dest}.backup.${Date.now()}`;
134
+ fs.copyFileSync(dest, backup);
135
+ console.log(`[noah] Backed up existing ${file} to ${path.basename(backup)}`);
136
+ }
137
+ if (TEMPLATED_FILES.has(file)) {
138
+ const content = fs.readFileSync(src, "utf-8");
139
+ const templated = applyTemplate(content, templateValues);
140
+ fs.writeFileSync(dest, templated);
141
+ console.log(`[noah] Installed ${file} (templated with config values)`);
142
+ }
143
+ else {
144
+ fs.copyFileSync(src, dest);
145
+ console.log(`[noah] Installed ${file}`);
146
+ }
147
+ }
148
+ // ── Step 4: Update openclaw.json ──────────────────────────────
149
+ let config;
150
+ try {
151
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
152
+ }
153
+ catch {
154
+ console.error(`[noah] ERROR: Could not parse ${configPath}`);
155
+ process.exitCode = 1;
156
+ return;
157
+ }
158
+ // Ensure agents.list exists
159
+ if (!config.agents)
160
+ config.agents = {};
161
+ if (!Array.isArray(config.agents.list))
162
+ config.agents.list = [];
163
+ // Check if noah agent already exists
164
+ const existingIdx = config.agents.list.findIndex((a) => a.id === "noah");
165
+ const noahAgentEntry = {
166
+ id: "noah",
167
+ name: "noah",
168
+ workspace: workspaceDir,
169
+ agentDir: agentDir,
170
+ model: model,
171
+ tools: {
172
+ allow: [
173
+ "noah_status",
174
+ "noah_trajectory",
175
+ "noah_setup",
176
+ "group:fs",
177
+ ],
178
+ },
179
+ };
180
+ if (existingIdx >= 0) {
181
+ if (force) {
182
+ config.agents.list[existingIdx] = noahAgentEntry;
183
+ console.log("[noah] Updated existing noah agent entry in openclaw.json");
184
+ }
185
+ else {
186
+ console.log("[noah] Noah agent already exists in agents.list (use --force to update)");
187
+ }
188
+ }
189
+ else {
190
+ config.agents.list.push(noahAgentEntry);
191
+ console.log("[noah] Added noah to agents.list in openclaw.json");
192
+ }
193
+ // ── Step 5: Configure Health Check Key if provided ────────────
194
+ if (options.healthCheckKey) {
195
+ if (!config.plugins)
196
+ config.plugins = {};
197
+ if (!config.plugins.entries)
198
+ config.plugins.entries = {};
199
+ if (!config.plugins.entries.noah) {
200
+ config.plugins.entries.noah = { enabled: true, config: {} };
201
+ }
202
+ if (!config.plugins.entries.noah.config) {
203
+ config.plugins.entries.noah.config = {};
204
+ }
205
+ config.plugins.entries.noah.config.healthCheckKey =
206
+ options.healthCheckKey;
207
+ console.log(`[noah] Health Check Key configured: ${options.healthCheckKey.substring(0, 8)}${"*".repeat(12)}`);
208
+ }
209
+ // ── Step 6: Write updated config ──────────────────────────────
210
+ // Atomic write: temp file + rename
211
+ const tmpPath = configPath + ".noah-setup.tmp";
212
+ fs.writeFileSync(tmpPath, JSON.stringify(config, null, 2));
213
+ fs.renameSync(tmpPath, configPath);
214
+ console.log("[noah] Updated openclaw.json");
215
+ // ── Done ──────────────────────────────────────────────────────
216
+ console.log("");
217
+ console.log("╔══════════════════════════════════════════╗");
218
+ console.log("║ Noah agent setup complete! ║");
219
+ console.log("╚══════════════════════════════════════════╝");
220
+ console.log("");
221
+ console.log(" Agent directory: " + agentDir);
222
+ console.log(" Workspace: " + workspaceDir);
223
+ console.log(" Data directory: " + dataDir);
224
+ console.log(" Model: " + model);
225
+ console.log("");
226
+ if (!options.healthCheckKey) {
227
+ console.log(" NEXT STEP: Add your Health Check Key to openclaw.json:");
228
+ console.log(' plugins.entries.noah.config.healthCheckKey = "hck_..."');
229
+ console.log("");
230
+ }
231
+ console.log(" Restart OpenClaw to activate Noah:");
232
+ console.log(" systemctl restart openclaw-gateway");
233
+ console.log(" # or: openclaw gateway restart");
234
+ console.log("");
235
+ console.log(" Then message Noah directly to verify: 'Noah, status'");
236
+ }
237
+ //# sourceMappingURL=setup.js.map