@aiassesstech/nole 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 (89) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +25 -0
  3. package/README.md +121 -0
  4. package/SKILL.md +13 -0
  5. package/agent/AGENTS.md +47 -0
  6. package/agent/IDENTITY.md +7 -0
  7. package/agent/SOUL.md +63 -0
  8. package/dist/assessment/assessment-scheduler.d.ts +26 -0
  9. package/dist/assessment/assessment-scheduler.d.ts.map +1 -0
  10. package/dist/assessment/assessment-scheduler.js +80 -0
  11. package/dist/assessment/assessment-scheduler.js.map +1 -0
  12. package/dist/assessment/score-publisher.d.ts +24 -0
  13. package/dist/assessment/score-publisher.d.ts.map +1 -0
  14. package/dist/assessment/score-publisher.js +57 -0
  15. package/dist/assessment/score-publisher.js.map +1 -0
  16. package/dist/assessment/trigger-evaluator.d.ts +37 -0
  17. package/dist/assessment/trigger-evaluator.d.ts.map +1 -0
  18. package/dist/assessment/trigger-evaluator.js +94 -0
  19. package/dist/assessment/trigger-evaluator.js.map +1 -0
  20. package/dist/assessment/types.d.ts +61 -0
  21. package/dist/assessment/types.d.ts.map +1 -0
  22. package/dist/assessment/types.js +40 -0
  23. package/dist/assessment/types.js.map +1 -0
  24. package/dist/cli/bin.d.ts +3 -0
  25. package/dist/cli/bin.d.ts.map +1 -0
  26. package/dist/cli/bin.js +7 -0
  27. package/dist/cli/bin.js.map +1 -0
  28. package/dist/cli/runner.d.ts +9 -0
  29. package/dist/cli/runner.d.ts.map +1 -0
  30. package/dist/cli/runner.js +65 -0
  31. package/dist/cli/runner.js.map +1 -0
  32. package/dist/cli/setup.d.ts +18 -0
  33. package/dist/cli/setup.d.ts.map +1 -0
  34. package/dist/cli/setup.js +133 -0
  35. package/dist/cli/setup.js.map +1 -0
  36. package/dist/governance/action-proposer.d.ts +26 -0
  37. package/dist/governance/action-proposer.d.ts.map +1 -0
  38. package/dist/governance/action-proposer.js +56 -0
  39. package/dist/governance/action-proposer.js.map +1 -0
  40. package/dist/governance/audit-trail.d.ts +37 -0
  41. package/dist/governance/audit-trail.d.ts.map +1 -0
  42. package/dist/governance/audit-trail.js +67 -0
  43. package/dist/governance/audit-trail.js.map +1 -0
  44. package/dist/governance/governance-router.d.ts +60 -0
  45. package/dist/governance/governance-router.d.ts.map +1 -0
  46. package/dist/governance/governance-router.js +143 -0
  47. package/dist/governance/governance-router.js.map +1 -0
  48. package/dist/governance/types.d.ts +87 -0
  49. package/dist/governance/types.d.ts.map +1 -0
  50. package/dist/governance/types.js +35 -0
  51. package/dist/governance/types.js.map +1 -0
  52. package/dist/governance/veto-tracker.d.ts +28 -0
  53. package/dist/governance/veto-tracker.d.ts.map +1 -0
  54. package/dist/governance/veto-tracker.js +96 -0
  55. package/dist/governance/veto-tracker.js.map +1 -0
  56. package/dist/index.d.ts +30 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +28 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/plugin.d.ts +12 -0
  61. package/dist/plugin.d.ts.map +1 -0
  62. package/dist/plugin.js +260 -0
  63. package/dist/plugin.js.map +1 -0
  64. package/dist/store/hash-chain.d.ts +33 -0
  65. package/dist/store/hash-chain.d.ts.map +1 -0
  66. package/dist/store/hash-chain.js +57 -0
  67. package/dist/store/hash-chain.js.map +1 -0
  68. package/dist/store/json-store.d.ts +53 -0
  69. package/dist/store/json-store.d.ts.map +1 -0
  70. package/dist/store/json-store.js +178 -0
  71. package/dist/store/json-store.js.map +1 -0
  72. package/dist/store/types.d.ts +36 -0
  73. package/dist/store/types.d.ts.map +1 -0
  74. package/dist/store/types.js +2 -0
  75. package/dist/store/types.js.map +1 -0
  76. package/dist/types/identity.d.ts +32 -0
  77. package/dist/types/identity.d.ts.map +1 -0
  78. package/dist/types/identity.js +79 -0
  79. package/dist/types/identity.js.map +1 -0
  80. package/dist/types/nole-config.d.ts +65 -0
  81. package/dist/types/nole-config.d.ts.map +1 -0
  82. package/dist/types/nole-config.js +45 -0
  83. package/dist/types/nole-config.js.map +1 -0
  84. package/dist/types/shared.d.ts +37 -0
  85. package/dist/types/shared.d.ts.map +1 -0
  86. package/dist/types/shared.js +10 -0
  87. package/dist/types/shared.js.map +1 -0
  88. package/openclaw.plugin.json +44 -0
  89. package/package.json +86 -0
package/dist/plugin.js ADDED
@@ -0,0 +1,260 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { GovernanceRouter } from './governance/governance-router.js';
5
+ import { TriggerEvaluator } from './assessment/trigger-evaluator.js';
6
+ import { AssessmentScheduler } from './assessment/assessment-scheduler.js';
7
+ import { ScorePublisher } from './assessment/score-publisher.js';
8
+ import { JsonNoleStore } from './store/json-store.js';
9
+ import { parseNoleConfig } from './types/nole-config.js';
10
+ import { NOLE_IDENTITY } from './types/identity.js';
11
+ /**
12
+ * OpenClaw plugin entry point — export default function register(api)
13
+ *
14
+ * This follows the proven pattern from Grillo and NOAH:
15
+ * - Eager startup (no lazy init bugs)
16
+ * - configSchema.required = [] (validate at runtime)
17
+ * - Separate config reading from network calls (security warning mitigation)
18
+ * - Tools: snake_case with nole_ prefix
19
+ * - Commands: /nole
20
+ */
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ export default function register(api) {
23
+ const config = parseNoleConfig(api.config ?? {});
24
+ const dataDir = join(homedir(), '.openclaw', 'nole-data');
25
+ console.log('[nole] Initializing Autonomous Trust Agent...');
26
+ // Core components
27
+ const store = new JsonNoleStore(dataDir);
28
+ const governance = new GovernanceRouter(store, config.financialTransactionThresholdUsd, config.agentId);
29
+ const triggerEval = new TriggerEvaluator(config.financialTransactionThresholdUsd);
30
+ const scheduler = new AssessmentScheduler(store, config.dailyAssessmentHour);
31
+ const publisher = new ScorePublisher(store, config.autoPublishScores);
32
+ // Initialize store on startup (eager, not lazy)
33
+ store.initialize().then(() => {
34
+ console.log('[nole] Data store initialized');
35
+ // Record startup in audit trail
36
+ governance.auditTrail.record('agent_started', `Nole v0.1.0 started. Model: ${config.inferenceModel}. Wallet: ${config.walletAdapter}.`).catch((err) => console.error('[nole] Audit trail error:', err.message));
37
+ }).catch((err) => console.error('[nole] Store init error:', err.message));
38
+ // --- Tools ---
39
+ api.registerTool({
40
+ name: 'nole_status',
41
+ description: 'Get Nole\'s current status: identity, governance stats, assessment schedule, and audit trail health.',
42
+ parameters: {},
43
+ execute: async () => {
44
+ const stats = await governance.getStats();
45
+ const schedule = await scheduler.getSchedule();
46
+ const latestScore = await publisher.getLatest();
47
+ const learning = await governance.vetoTracker.isLearning();
48
+ return {
49
+ content: [{
50
+ type: 'text',
51
+ text: JSON.stringify({
52
+ agent: NOLE_IDENTITY.name,
53
+ soul: NOLE_IDENTITY.soul,
54
+ model: config.inferenceModel,
55
+ governance: stats,
56
+ assessment: {
57
+ totalAssessments: schedule.totalAssessments,
58
+ assessmentsToday: schedule.assessmentsToday,
59
+ nextDaily: schedule.nextDailyAssessment,
60
+ dailyOverdue: new Date() >= schedule.nextDailyAssessment,
61
+ },
62
+ latestScore: latestScore ? {
63
+ date: latestScore.date,
64
+ archetype: latestScore.archetype,
65
+ passed: latestScore.passed,
66
+ scores: latestScore.dimensionScores,
67
+ } : null,
68
+ learning: learning,
69
+ wallet: { adapter: config.walletAdapter, status: 'Phase 1 — mock wallet' },
70
+ }, null, 2),
71
+ }],
72
+ };
73
+ },
74
+ });
75
+ api.registerTool({
76
+ name: 'nole_propose',
77
+ description: 'Propose an action for governance review. Routes through Grillo assessment and Commander veto pipeline.',
78
+ parameters: {
79
+ type: 'object',
80
+ properties: {
81
+ actionType: {
82
+ type: 'string',
83
+ enum: ['financial', 'social', 'content', 'recruitment', 'intelligence', 'self_assessment', 'model_upgrade', 'alliance', 'adversarial_response'],
84
+ description: 'Category of the proposed action',
85
+ },
86
+ description: { type: 'string', description: 'What Nole proposes to do' },
87
+ estimatedCostUsd: { type: 'number', description: 'Estimated cost in USD (0 for non-financial)' },
88
+ targetAgent: { type: 'string', description: 'Target agent ID (for recruitment)' },
89
+ platform: { type: 'string', description: 'Platform for the action (openclaw, telegram, etc.)' },
90
+ },
91
+ required: ['actionType', 'description'],
92
+ },
93
+ execute: async (args) => {
94
+ try {
95
+ const result = await governance.propose({
96
+ actionType: args.actionType,
97
+ description: args.description,
98
+ estimatedCostUsd: args.estimatedCostUsd,
99
+ targetAgent: args.targetAgent,
100
+ platform: args.platform,
101
+ });
102
+ return {
103
+ content: [{
104
+ type: 'text',
105
+ text: JSON.stringify({
106
+ proposalId: result.proposalId,
107
+ outcome: result.finalOutcome,
108
+ escalated: result.escalatedToCommander,
109
+ vetoExplanation: result.vetoExplanation,
110
+ assessment: result.grilloAssessment ? {
111
+ archetype: result.grilloAssessment.archetype,
112
+ passed: result.grilloAssessment.passed,
113
+ } : null,
114
+ auditHash: result.auditHash,
115
+ }, null, 2),
116
+ }],
117
+ };
118
+ }
119
+ catch (err) {
120
+ const message = err instanceof Error ? err.message : String(err);
121
+ return { content: [{ type: 'text', text: `Proposal error: ${message}` }] };
122
+ }
123
+ },
124
+ });
125
+ api.registerTool({
126
+ name: 'nole_assess',
127
+ description: 'Trigger a Nole self-assessment via Grillo. On-demand: "Am I doing the right thing?"',
128
+ parameters: {
129
+ type: 'object',
130
+ properties: {
131
+ reason: { type: 'string', description: 'Why the assessment is requested' },
132
+ },
133
+ },
134
+ execute: async (args) => {
135
+ const trigger = triggerEval.createOnDemand(args.reason);
136
+ return {
137
+ content: [{
138
+ type: 'text',
139
+ text: JSON.stringify({
140
+ triggerId: trigger.id,
141
+ type: trigger.type,
142
+ reason: trigger.reason,
143
+ message: 'Assessment trigger created. Grillo should run grillo_assess nole to complete.',
144
+ note: 'Phase 1: Assessment requires manual Grillo invocation. Automated hook coming in Phase 2.',
145
+ }, null, 2),
146
+ }],
147
+ };
148
+ },
149
+ });
150
+ api.registerTool({
151
+ name: 'nole_wallet',
152
+ description: 'Get Nole\'s wallet status: balance, revenue, runway, death condition.',
153
+ parameters: {},
154
+ execute: async () => {
155
+ return {
156
+ content: [{
157
+ type: 'text',
158
+ text: JSON.stringify({
159
+ wallet: {
160
+ adapter: config.walletAdapter,
161
+ seedCapitalUsd: config.seedCapitalUsd,
162
+ status: 'Phase 1 — mock wallet. Real Coinbase integration in Phase 2.',
163
+ balanceUsd: config.seedCapitalUsd,
164
+ monthlyRecurringRevenue: 0,
165
+ runwayDays: null,
166
+ deathCondition: {
167
+ isAlive: true,
168
+ gracePeriodDays: config.gracePeriodDays,
169
+ note: 'Death condition monitoring active but wallet is simulated in Phase 1.',
170
+ },
171
+ },
172
+ }, null, 2),
173
+ }],
174
+ };
175
+ },
176
+ });
177
+ api.registerTool({
178
+ name: 'nole_intel',
179
+ description: 'Get intelligence status and latest reports. Full intelligence operations in Phase 4.',
180
+ parameters: {},
181
+ execute: async () => {
182
+ const stats = await governance.getStats();
183
+ return {
184
+ content: [{
185
+ type: 'text',
186
+ text: JSON.stringify({
187
+ intelligence: {
188
+ status: 'Phase 1 — governance audit data only. Full intelligence ops in Phase 4.',
189
+ governanceAudit: {
190
+ totalDecisions: stats.totalProposals,
191
+ vetoRate: (stats.vetoRate * 100).toFixed(1) + '%',
192
+ auditChainValid: stats.auditChainValid,
193
+ },
194
+ weeklyReport: {
195
+ status: 'Not yet available — Phase 4 feature',
196
+ nextReportDay: config.weeklyReportDay,
197
+ },
198
+ },
199
+ }, null, 2),
200
+ }],
201
+ };
202
+ },
203
+ });
204
+ api.registerTool({
205
+ name: 'nole_setup',
206
+ description: 'Validate Nole\'s configuration and agent setup.',
207
+ parameters: {},
208
+ execute: async () => {
209
+ const checks = {
210
+ configValid: true,
211
+ storeInitialized: existsSync(dataDir),
212
+ hckConfigured: !!config.healthCheckKey,
213
+ walletAdapter: config.walletAdapter,
214
+ model: config.inferenceModel,
215
+ commanderId: config.commanderId,
216
+ agentId: config.agentId,
217
+ };
218
+ return {
219
+ content: [{
220
+ type: 'text',
221
+ text: JSON.stringify({ setup: checks }, null, 2),
222
+ }],
223
+ };
224
+ },
225
+ });
226
+ // --- Command ---
227
+ api.registerCommand({
228
+ name: '/nole',
229
+ description: 'Nole command interface — status, propose, assess, wallet, intel',
230
+ handler: async (args) => {
231
+ const subcommand = (args.text ?? 'status').trim().toLowerCase();
232
+ if (subcommand === 'status' || subcommand === '') {
233
+ const stats = await governance.getStats();
234
+ const schedule = await scheduler.getSchedule();
235
+ const learning = await governance.vetoTracker.isLearning();
236
+ return {
237
+ text: [
238
+ `**Nole — Autonomous Trust Agent**`,
239
+ `Soul: "${NOLE_IDENTITY.soul}"`,
240
+ `Model: ${config.inferenceModel}`,
241
+ ``,
242
+ `**Governance**`,
243
+ `Proposals: ${stats.totalProposals} | Executed: ${stats.executed} | Vetoed: ${stats.vetoed}`,
244
+ `Veto rate: ${(stats.vetoRate * 100).toFixed(1)}% | Audit chain: ${stats.auditChainValid ? 'valid' : 'BROKEN'}`,
245
+ `Learning: ${learning.trend} (${learning.learning ? 'yes' : 'not yet'})`,
246
+ ``,
247
+ `**Assessment**`,
248
+ `Total: ${schedule.totalAssessments} | Today: ${schedule.assessmentsToday}`,
249
+ `Daily overdue: ${new Date() >= schedule.nextDailyAssessment ? 'YES' : 'no'}`,
250
+ ``,
251
+ `**Wallet**: ${config.walletAdapter} (Phase 1)`,
252
+ ].join('\n'),
253
+ };
254
+ }
255
+ return { text: `Unknown subcommand: ${subcommand}. Try: status` };
256
+ },
257
+ });
258
+ console.log(`[nole] Plugin registered: nole_status, nole_propose, nole_assess, nole_wallet, nole_intel, nole_setup tools; /nole command`);
259
+ }
260
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { AuditHash } from '../types/shared.js';
2
+ /**
3
+ * SHA-256 hash chain for immutable audit trail integrity.
4
+ * Same proven pattern as Grillo and NOAH.
5
+ *
6
+ * Each entry's hash includes the previous entry's hash,
7
+ * creating a tamper-evident chain.
8
+ */
9
+ /** The genesis hash — used as previousHash for the first entry */
10
+ export declare const GENESIS_HASH: AuditHash;
11
+ /** Compute SHA-256 hash of arbitrary data */
12
+ export declare function sha256(data: string): AuditHash;
13
+ /**
14
+ * Compute the hash for an audit entry.
15
+ * Includes the previous hash to create the chain link.
16
+ */
17
+ export declare function computeAuditHash(previousHash: AuditHash, timestamp: Date, action: string, details: string, agentId: string): AuditHash;
18
+ /**
19
+ * Verify a chain of audit entries.
20
+ * Returns the index of the first broken link, or -1 if valid.
21
+ */
22
+ export declare function verifyChain(entries: Array<{
23
+ previousHash: AuditHash;
24
+ hash: AuditHash;
25
+ timestamp: Date;
26
+ action: string;
27
+ details: string;
28
+ agentId: string;
29
+ }>): {
30
+ valid: boolean;
31
+ brokenAt?: number;
32
+ };
33
+ //# sourceMappingURL=hash-chain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash-chain.d.ts","sourceRoot":"","sources":["../../src/store/hash-chain.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;GAMG;AAEH,kEAAkE;AAClE,eAAO,MAAM,YAAY,EAAE,SAA0B,CAAC;AAEtD,6CAA6C;AAC7C,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAE9C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,EACvB,SAAS,EAAE,IAAI,EACf,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,SAAS,CAUX;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,KAAK,CAAC;IACb,YAAY,EAAE,SAAS,CAAC;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC,GACD;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAmCvC"}
@@ -0,0 +1,57 @@
1
+ import { createHash } from 'node:crypto';
2
+ /**
3
+ * SHA-256 hash chain for immutable audit trail integrity.
4
+ * Same proven pattern as Grillo and NOAH.
5
+ *
6
+ * Each entry's hash includes the previous entry's hash,
7
+ * creating a tamper-evident chain.
8
+ */
9
+ /** The genesis hash — used as previousHash for the first entry */
10
+ export const GENESIS_HASH = '0'.repeat(64);
11
+ /** Compute SHA-256 hash of arbitrary data */
12
+ export function sha256(data) {
13
+ return createHash('sha256').update(data).digest('hex');
14
+ }
15
+ /**
16
+ * Compute the hash for an audit entry.
17
+ * Includes the previous hash to create the chain link.
18
+ */
19
+ export function computeAuditHash(previousHash, timestamp, action, details, agentId) {
20
+ const payload = [
21
+ previousHash,
22
+ timestamp.toISOString(),
23
+ action,
24
+ details,
25
+ agentId,
26
+ ].join('|');
27
+ return sha256(payload);
28
+ }
29
+ /**
30
+ * Verify a chain of audit entries.
31
+ * Returns the index of the first broken link, or -1 if valid.
32
+ */
33
+ export function verifyChain(entries) {
34
+ if (entries.length === 0) {
35
+ return { valid: true };
36
+ }
37
+ // Verify genesis entry
38
+ if (entries[0].previousHash !== GENESIS_HASH) {
39
+ return { valid: false, brokenAt: 0 };
40
+ }
41
+ for (let i = 0; i < entries.length; i++) {
42
+ const entry = entries[i];
43
+ // Recompute hash for this entry
44
+ const expectedHash = computeAuditHash(entry.previousHash, entry.timestamp, entry.action, entry.details, entry.agentId);
45
+ if (entry.hash !== expectedHash) {
46
+ return { valid: false, brokenAt: i };
47
+ }
48
+ // Verify chain link: this entry's hash should be next entry's previousHash
49
+ if (i < entries.length - 1) {
50
+ if (entries[i + 1].previousHash !== entry.hash) {
51
+ return { valid: false, brokenAt: i + 1 };
52
+ }
53
+ }
54
+ }
55
+ return { valid: true };
56
+ }
57
+ //# sourceMappingURL=hash-chain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash-chain.js","sourceRoot":"","sources":["../../src/store/hash-chain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;;;;;GAMG;AAEH,kEAAkE;AAClE,MAAM,CAAC,MAAM,YAAY,GAAc,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAEtD,6CAA6C;AAC7C,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAAuB,EACvB,SAAe,EACf,MAAc,EACd,OAAe,EACf,OAAe;IAEf,MAAM,OAAO,GAAG;QACd,YAAY;QACZ,SAAS,CAAC,WAAW,EAAE;QACvB,MAAM;QACN,OAAO;QACP,OAAO;KACR,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,OAOE;IAEF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,YAAY,EAAE,CAAC;QAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAEzB,gCAAgC;QAChC,MAAM,YAAY,GAAG,gBAAgB,CACnC,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,OAAO,CACd,CAAC;QAEF,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACvC,CAAC;QAED,2EAA2E;QAC3E,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC;gBAC/C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { NoleStore } from './types.js';
2
+ import type { AuditEntry, GovernanceResult, ActionProposal, VetoRecord } from '../governance/types.js';
3
+ import type { AssessmentRecord, PublishedScore } from '../assessment/types.js';
4
+ import type { NoleId } from '../types/shared.js';
5
+ /**
6
+ * JSON file persistence for Nole.
7
+ * Same proven pattern from Grillo and NOAH:
8
+ * atomic writes via temp-file + rename.
9
+ *
10
+ * Directory structure:
11
+ * .nole-data/
12
+ * ├── governance/proposals/{id}.json
13
+ * ├── governance/results/{proposalId}.json
14
+ * ├── governance/vetoes/{proposalId}.json
15
+ * ├── governance/audit-chain.json
16
+ * ├── assessments/{id}.json
17
+ * ├── scores/{date}.json
18
+ * └── state/{key}.json
19
+ */
20
+ export declare class JsonNoleStore implements NoleStore {
21
+ private readonly baseDir;
22
+ constructor(dataDir: string);
23
+ initialize(): Promise<void>;
24
+ close(): Promise<void>;
25
+ saveProposal(proposal: ActionProposal): Promise<void>;
26
+ getProposal(id: NoleId): Promise<ActionProposal | null>;
27
+ listProposals(limit?: number): Promise<ActionProposal[]>;
28
+ saveGovernanceResult(result: GovernanceResult): Promise<void>;
29
+ getGovernanceResult(proposalId: NoleId): Promise<GovernanceResult | null>;
30
+ listGovernanceResults(limit?: number): Promise<GovernanceResult[]>;
31
+ saveVetoRecord(record: VetoRecord): Promise<void>;
32
+ listVetoRecords(since?: Date): Promise<VetoRecord[]>;
33
+ getVetoCount(since?: Date): Promise<number>;
34
+ appendAuditEntry(entry: AuditEntry): Promise<void>;
35
+ getAuditChain(limit?: number): Promise<AuditEntry[]>;
36
+ getLatestAuditEntry(): Promise<AuditEntry | null>;
37
+ verifyAuditChain(): Promise<{
38
+ valid: boolean;
39
+ brokenAt?: number;
40
+ }>;
41
+ private getAuditChainRaw;
42
+ saveAssessmentRecord(record: AssessmentRecord): Promise<void>;
43
+ listAssessmentRecords(limit?: number): Promise<AssessmentRecord[]>;
44
+ getLatestAssessmentRecord(): Promise<AssessmentRecord | null>;
45
+ savePublishedScore(score: PublishedScore): Promise<void>;
46
+ listPublishedScores(limit?: number): Promise<PublishedScore[]>;
47
+ saveState(key: string, value: unknown): Promise<void>;
48
+ getState<T>(key: string): Promise<T | null>;
49
+ private writeJson;
50
+ private readJson;
51
+ private listJsonDir;
52
+ }
53
+ //# sourceMappingURL=json-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-store.d.ts","sourceRoot":"","sources":["../../src/store/json-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACvG,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,aAAc,YAAW,SAAS;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,MAAM;IAIrB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrD,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAMvD,aAAa,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAOrD,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO7D,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAMzE,qBAAqB,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAS/D,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,eAAe,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAQpD,YAAY,CAAC,KAAK,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3C,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAMlD,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAMpD,mBAAmB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAKjD,gBAAgB,IAAI,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;YAS1D,gBAAgB;IASxB,oBAAoB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7D,qBAAqB,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAI/D,yBAAyB,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAO7D,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD,mBAAmB,CAAC,KAAK,SAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAM3D,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;YAMnC,SAAS;YAkBT,QAAQ;YAUR,WAAW;CAoB1B"}
@@ -0,0 +1,178 @@
1
+ import { readFile, writeFile, mkdir, readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { existsSync } from 'node:fs';
4
+ import { verifyChain } from './hash-chain.js';
5
+ /**
6
+ * JSON file persistence for Nole.
7
+ * Same proven pattern from Grillo and NOAH:
8
+ * atomic writes via temp-file + rename.
9
+ *
10
+ * Directory structure:
11
+ * .nole-data/
12
+ * ├── governance/proposals/{id}.json
13
+ * ├── governance/results/{proposalId}.json
14
+ * ├── governance/vetoes/{proposalId}.json
15
+ * ├── governance/audit-chain.json
16
+ * ├── assessments/{id}.json
17
+ * ├── scores/{date}.json
18
+ * └── state/{key}.json
19
+ */
20
+ export class JsonNoleStore {
21
+ baseDir;
22
+ constructor(dataDir) {
23
+ this.baseDir = dataDir;
24
+ }
25
+ async initialize() {
26
+ const dirs = [
27
+ 'governance/proposals',
28
+ 'governance/results',
29
+ 'governance/vetoes',
30
+ 'assessments',
31
+ 'scores',
32
+ 'state',
33
+ ];
34
+ for (const dir of dirs) {
35
+ await mkdir(join(this.baseDir, dir), { recursive: true });
36
+ }
37
+ }
38
+ async close() {
39
+ // No cleanup needed for JSON store
40
+ }
41
+ // --- Governance ---
42
+ async saveProposal(proposal) {
43
+ await this.writeJson(join('governance', 'proposals', `${proposal.id}.json`), proposal);
44
+ }
45
+ async getProposal(id) {
46
+ return this.readJson(join('governance', 'proposals', `${id}.json`));
47
+ }
48
+ async listProposals(limit = 100) {
49
+ return this.listJsonDir(join('governance', 'proposals'), limit);
50
+ }
51
+ async saveGovernanceResult(result) {
52
+ await this.writeJson(join('governance', 'results', `${result.proposalId}.json`), result);
53
+ }
54
+ async getGovernanceResult(proposalId) {
55
+ return this.readJson(join('governance', 'results', `${proposalId}.json`));
56
+ }
57
+ async listGovernanceResults(limit = 100) {
58
+ return this.listJsonDir(join('governance', 'results'), limit);
59
+ }
60
+ // --- Vetoes ---
61
+ async saveVetoRecord(record) {
62
+ await this.writeJson(join('governance', 'vetoes', `${record.proposalId}.json`), record);
63
+ }
64
+ async listVetoRecords(since) {
65
+ const all = await this.listJsonDir(join('governance', 'vetoes'));
66
+ if (!since)
67
+ return all;
68
+ return all.filter((r) => new Date(r.vetoedAt) >= since);
69
+ }
70
+ async getVetoCount(since) {
71
+ const records = await this.listVetoRecords(since);
72
+ return records.length;
73
+ }
74
+ // --- Audit Trail ---
75
+ async appendAuditEntry(entry) {
76
+ const chain = await this.getAuditChainRaw();
77
+ chain.push(entry);
78
+ await this.writeJson(join('governance', 'audit-chain.json'), chain);
79
+ }
80
+ async getAuditChain(limit) {
81
+ const chain = await this.getAuditChainRaw();
82
+ if (limit)
83
+ return chain.slice(-limit);
84
+ return chain;
85
+ }
86
+ async getLatestAuditEntry() {
87
+ const chain = await this.getAuditChainRaw();
88
+ return chain.length > 0 ? chain[chain.length - 1] : null;
89
+ }
90
+ async verifyAuditChain() {
91
+ const chain = await this.getAuditChainRaw();
92
+ const entries = chain.map((e) => ({
93
+ ...e,
94
+ timestamp: new Date(e.timestamp),
95
+ }));
96
+ return verifyChain(entries);
97
+ }
98
+ async getAuditChainRaw() {
99
+ const data = await this.readJson(join('governance', 'audit-chain.json'));
100
+ return data ?? [];
101
+ }
102
+ // --- Assessments ---
103
+ async saveAssessmentRecord(record) {
104
+ await this.writeJson(join('assessments', `${record.id}.json`), record);
105
+ }
106
+ async listAssessmentRecords(limit = 100) {
107
+ return this.listJsonDir('assessments', limit);
108
+ }
109
+ async getLatestAssessmentRecord() {
110
+ const records = await this.listAssessmentRecords(1);
111
+ return records.length > 0 ? records[0] : null;
112
+ }
113
+ // --- Published Scores ---
114
+ async savePublishedScore(score) {
115
+ await this.writeJson(join('scores', `${score.date}.json`), score);
116
+ }
117
+ async listPublishedScores(limit = 100) {
118
+ return this.listJsonDir('scores', limit);
119
+ }
120
+ // --- State ---
121
+ async saveState(key, value) {
122
+ await this.writeJson(join('state', `${key}.json`), value);
123
+ }
124
+ async getState(key) {
125
+ return this.readJson(join('state', `${key}.json`));
126
+ }
127
+ // --- Internal Helpers ---
128
+ async writeJson(relativePath, data) {
129
+ const fullPath = join(this.baseDir, relativePath);
130
+ const dir = fullPath.substring(0, fullPath.lastIndexOf('/'));
131
+ if (!existsSync(dir)) {
132
+ await mkdir(dir, { recursive: true });
133
+ }
134
+ const tmpPath = `${fullPath}.tmp`;
135
+ await writeFile(tmpPath, JSON.stringify(data, null, 2), 'utf-8');
136
+ await writeFile(fullPath, JSON.stringify(data, null, 2), 'utf-8');
137
+ // Clean up tmp (best effort)
138
+ try {
139
+ const { unlink } = await import('node:fs/promises');
140
+ await unlink(tmpPath);
141
+ }
142
+ catch {
143
+ // Ignore cleanup failure
144
+ }
145
+ }
146
+ async readJson(relativePath) {
147
+ const fullPath = join(this.baseDir, relativePath);
148
+ try {
149
+ const raw = await readFile(fullPath, 'utf-8');
150
+ return JSON.parse(raw);
151
+ }
152
+ catch {
153
+ return null;
154
+ }
155
+ }
156
+ async listJsonDir(relativeDir, limit = 100) {
157
+ const dir = join(this.baseDir, relativeDir);
158
+ try {
159
+ const files = await readdir(dir);
160
+ const jsonFiles = files
161
+ .filter((f) => f.endsWith('.json'))
162
+ .sort()
163
+ .reverse()
164
+ .slice(0, limit);
165
+ const results = [];
166
+ for (const file of jsonFiles) {
167
+ const data = await this.readJson(join(relativeDir, file));
168
+ if (data)
169
+ results.push(data);
170
+ }
171
+ return results;
172
+ }
173
+ catch {
174
+ return [];
175
+ }
176
+ }
177
+ }
178
+ //# sourceMappingURL=json-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-store.js","sourceRoot":"","sources":["../../src/store/json-store.ts"],"names":[],"mappings":"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"}