nodal-agents 0.8.6 → 0.8.7
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/cli.js +223 -32
- package/migrations/0082_entities_auto_run_paused.sql +32 -0
- package/migrations/0083_code_project_archives.sql +14 -0
- package/migrations/0084_release_wrong_auto_run_pause.sql +24 -0
- package/migrations/0085_workspaces_is_dev_folder.sql +33 -0
- package/migrations/0086_code_projects_rename_and_hide.sql +61 -0
- package/migrations/0087_workspaces_hidden_from_code.sql +44 -0
- package/migrations/meta/_journal.json +42 -0
- package/package.json +1 -1
- package/runner.js +2863 -1657
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +12 -12
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js +4 -4
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page.js +1 -1
- package/web/.next/server/app/(dashboard)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page.js +1 -1
- package/web/.next/server/app/(dashboard)/approvals/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page.js +1 -1
- package/web/.next/server/app/(dashboard)/automations/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/code/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/code/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/code/page.js +1 -1
- package/web/.next/server/app/(dashboard)/code/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js +1 -1
- package/web/.next/server/app/(dashboard)/connectors/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js +1 -1
- package/web/.next/server/app/(dashboard)/credentials/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page.js +1 -1
- package/web/.next/server/app/(dashboard)/jobs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page.js +1 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page.js +1 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page.js +1 -1
- package/web/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page.js +1 -1
- package/web/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page.js +1 -1
- package/web/.next/server/app/(dashboard)/memories/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page.js +3 -3
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page.js +1 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/new/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page.js +1 -1
- package/web/.next/server/app/(dashboard)/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error/page.js +1 -1
- package/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +1 -1
- package/web/.next/server/app/_global-error.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +3 -3
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page.js +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/server/app/_not-found.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +4 -4
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/api/auth/[...all]/route.js +1 -1
- package/web/.next/server/app/api/health/route.js +1 -1
- package/web/.next/server/app/login/page.js +1 -1
- package/web/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/onboarding/page.js +2 -2
- package/web/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app-paths-manifest.json +12 -12
- package/web/.next/server/chunks/1126.js +1 -1
- package/web/.next/server/chunks/210.js +1 -0
- package/web/.next/server/chunks/2834.js +1 -0
- package/web/.next/server/chunks/3666.js +1 -0
- package/web/.next/server/chunks/3756.js +1 -0
- package/web/.next/server/chunks/3927.js +1597 -0
- package/web/.next/server/chunks/42.js +2 -2
- package/web/.next/server/chunks/4869.js +1629 -0
- package/web/.next/server/chunks/5384.js +1 -0
- package/web/.next/server/chunks/7048.js +1 -0
- package/web/.next/server/chunks/7251.js +1 -0
- package/web/.next/server/chunks/7650.js +1749 -0
- package/web/.next/server/chunks/7741.js +1 -1
- package/web/.next/server/chunks/{5877.js → 8191.js} +71 -89
- package/web/.next/server/chunks/9949.js +1746 -0
- package/web/.next/server/middleware-build-manifest.js +1 -1
- package/web/.next/server/middleware.js +3 -3
- package/web/.next/server/pages/404.html +1 -1
- package/web/.next/server/pages/500.html +1 -1
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/server/webpack-runtime.js +1 -1
- package/web/.next/static/chunks/2515-a9fd443091bb4291.js +1 -0
- package/web/.next/static/chunks/5034-df0e39b679214174.js +1 -0
- package/web/.next/static/chunks/6306-6448703d936feed3.js +1629 -0
- package/web/.next/static/chunks/6646-60db74d7d175dba0.js +1 -0
- package/web/.next/static/chunks/8423-57a00fc00778c1e1.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-42261de6e1de3f0d.js +6 -0
- package/web/.next/static/chunks/app/(dashboard)/agents/page-b028af9e30e8fb83.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/approvals/{page-99ec2b36c44ed3d3.js → page-a752b0ddc39d34f4.js} +1 -1
- package/web/.next/static/chunks/app/(dashboard)/automations/page-521ded8178a4513f.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/chat/page-1042ea3f25d7b430.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/code/[id]/page-bed8be1148fb7d1d.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/code/page-b72af9e2731d0bb1.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-8a1993ba5a7ba872.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-522a1f164f88f89b.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-15d22e17291edb01.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/layout-09b1990c5a3a9a09.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-93aa992e100c0b5a.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-d121748077e7c685.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/logs/page-e4b6136ecf9ccd14.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-b762d306176a4851.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/memories/page-de710d983bae276e.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/{page-1e05fa622609cdf1.js → page-8b3f80ee2f3d8c11.js} +1 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/page-977685a40ec1a2f2.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-db8f2599cc9771e1.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-b8e71ad3ef0b27d4.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-0d777140d4c73ad8.js +1 -0
- package/web/.next/static/chunks/app/(dashboard)/skills/page-127e5d5374a4bb2a.js +1 -0
- package/web/.next/static/chunks/app/error-3d9af79e7856dcc8.js +1 -0
- package/web/.next/static/chunks/app/login/page-8d873e8ff103a226.js +1 -0
- package/web/.next/static/chunks/app/onboarding/{page-f02705f7710caa08.js → page-0145253536f365ee.js} +2 -2
- package/web/.next/static/css/be2ece2e5b18d112.css +3 -0
- package/web/.next/server/app/(dashboard)/agents/[id]/channels/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/edit/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/agents/[id]/telegram/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/agents/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/approvals/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/automations/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/code/[id]/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/code/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/connectors/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/credentials/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/jobs/[id]/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/jobs/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/learned-skills/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/llm-providers/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/logs/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/mcp/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/memories/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/settings/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/settings/root-context/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/skills/[id]/edit/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/skills/new/page.js.nft.json +0 -1
- package/web/.next/server/app/(dashboard)/skills/page.js.nft.json +0 -1
- package/web/.next/server/app/_global-error/page.js.nft.json +0 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/web/.next/server/app/api/auth/[...all]/route.js.nft.json +0 -1
- package/web/.next/server/app/api/health/route.js.nft.json +0 -1
- package/web/.next/server/app/api/oauth/[provider]/callback/route.js.nft.json +0 -1
- package/web/.next/server/app/api/oauth/[provider]/start/route.js.nft.json +0 -1
- package/web/.next/server/app/auth/callback/route.js.nft.json +0 -1
- package/web/.next/server/app/login/page.js.nft.json +0 -1
- package/web/.next/server/app/onboarding/page.js.nft.json +0 -1
- package/web/.next/server/chunks/2745.js +0 -1
- package/web/.next/server/chunks/2938.js +0 -1
- package/web/.next/server/chunks/4630.js +0 -1
- package/web/.next/server/chunks/4639.js +0 -1744
- package/web/.next/server/chunks/4711.js +0 -1
- package/web/.next/server/chunks/4924.js +0 -1741
- package/web/.next/server/chunks/5149.js +0 -1
- package/web/.next/server/chunks/6680.js +0 -1615
- package/web/.next/server/chunks/9729.js +0 -1
- package/web/.next/server/middleware.js.nft.json +0 -1
- package/web/.next/static/chunks/4994-7effa935c5703218.js +0 -1
- package/web/.next/static/chunks/5034-7b0857c231a2db7e.js +0 -1
- package/web/.next/static/chunks/8423-bf78a9de790d8ebc.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/agents/[id]/edit/page-f55badb51d6e10b1.js +0 -6
- package/web/.next/static/chunks/app/(dashboard)/agents/page-d256dbe832dfb238.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/automations/page-9242e9b754d98c68.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/chat/page-7f9c147e49730cb4.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/code/[id]/page-46acd3da2c78b6df.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/code/page-12598290e23cb30a.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/connectors/page-a67da30a55296b54.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/[id]/page-793efbdc85566e24.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/jobs/page-cce723799dad2458.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/layout-5976fd8a05f7cefd.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/learned-skills/page-0f3b9332eeaf4282.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/llm-providers/page-4e0fef0a652f4e8a.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/logs/page-31b25388df6e0212.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/mcp/page-2364c615affa47d3.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/memories/page-52944e872698b85f.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/page-19ac2c3c794fa0f7.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/settings/root-context/page-cb20f211b06e807f.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/[id]/edit/page-5bc99166041fcf0d.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/new/page-453b7333a310658c.js +0 -1
- package/web/.next/static/chunks/app/(dashboard)/skills/page-055a17f39f670958.js +0 -1
- package/web/.next/static/chunks/app/error-d7d2badaa59bb441.js +0 -1
- package/web/.next/static/chunks/app/login/page-02aa17b387bdb416.js +0 -1
- package/web/.next/static/css/f0904e0d2f4e1435.css +0 -3
- /package/web/.next/static/{PMZOOK9t9OB35ORr4mOpd → FW6WAOvY3tiwZHzAR2ZUZ}/_buildManifest.js +0 -0
- /package/web/.next/static/{PMZOOK9t9OB35ORr4mOpd → FW6WAOvY3tiwZHzAR2ZUZ}/_ssgManifest.js +0 -0
package/cli.js
CHANGED
|
@@ -13500,11 +13500,19 @@ var init_entities = __esm({
|
|
|
13500
13500
|
// Controls whether agent-authored skills are auto-assigned to the authoring
|
|
13501
13501
|
// agent ('auto') or queued for the entity owner to approve ('approval').
|
|
13502
13502
|
skillAssignmentMode: text("skill_assignment_mode").notNull().default("approval").$type(),
|
|
13503
|
-
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13503
|
+
/**
|
|
13504
|
+
* Frein d'urgence de l'auto-exécution (0082, inversion du modèle à deux
|
|
13505
|
+
* clés — décision Quentin 24/08). true = TOUT l'auto-run de code du
|
|
13506
|
+
* workspace est en pause : les règles auto_approve des outils d'exécution
|
|
13507
|
+
* (run_command, code_task, scripts, MCP stdio) deviennent dormantes sans
|
|
13508
|
+
* être supprimées — le runner les déshabille à l'exécution. false
|
|
13509
|
+
* (défaut) = les toggles Yolo par agent (owner-only) s'appliquent tels
|
|
13510
|
+
* quels. Remplace lan_command_yolo, qui était une PRÉ-CONDITION
|
|
13511
|
+
* d'activation : redondante (les toggles par agent étaient déjà
|
|
13512
|
+
* owner-only) et pénible — sa vraie valeur était le coupe-circuit, qui
|
|
13513
|
+
* devient son seul rôle.
|
|
13514
|
+
*/
|
|
13515
|
+
autoRunPaused: boolean("auto_run_paused").notNull().default(false),
|
|
13508
13516
|
/**
|
|
13509
13517
|
* Interrupteur maitre du serveur MCP (PR C, decision Quentin 23/08).
|
|
13510
13518
|
* Defaut FERME : un point d'entree externe qui cree des jobs doit etre
|
|
@@ -13654,12 +13662,16 @@ var init_agents = __esm({
|
|
|
13654
13662
|
// action layer guarantees at least one provider stays enabled.
|
|
13655
13663
|
cliDefaults: jsonb("cli_defaults").$type(),
|
|
13656
13664
|
// Which harness drives this agent (étape E). 'nodal' (default) = the
|
|
13657
|
-
// Nodal runner loop. 'claude-code' = the agent IS a
|
|
13658
|
-
// persona from DB
|
|
13659
|
-
//
|
|
13660
|
-
//
|
|
13661
|
-
//
|
|
13662
|
-
//
|
|
13665
|
+
// Nodal runner loop. 'claude-code' and 'codex' = the agent IS a session of
|
|
13666
|
+
// that CLI: persona from DB, channels/cron/workspaces/budget/approvals stay
|
|
13667
|
+
// Nodal's, but the LOOP, tools and context are the CLI's — said as-is to
|
|
13668
|
+
// the user (dispatcher, not brain). A DATA field, never a hardcoded
|
|
13669
|
+
// per-agent branch (invariant #1).
|
|
13670
|
+
//
|
|
13671
|
+
// 'codex' a été RÉSERVÉ ici du 19/08 au 27/08 : accepté par la contrainte,
|
|
13672
|
+
// refusé par le Zod de l'action et par le runner. Ouvert le 27/08 —
|
|
13673
|
+
// apps/runner/src/cli-runtime/provider.ts porte désormais LE tableau des
|
|
13674
|
+
// runtimes servis ; cette contrainte et lui doivent rester d'accord.
|
|
13663
13675
|
runtime: text("runtime").default("nodal").notNull(),
|
|
13664
13676
|
// Runtime-agent permission posture, as DATA: mode 'read' (default when
|
|
13665
13677
|
// NULL) hides the CLI's write tools; 'write' allows workspace edits
|
|
@@ -14621,6 +14633,35 @@ var init_mcp = __esm({
|
|
|
14621
14633
|
}
|
|
14622
14634
|
});
|
|
14623
14635
|
|
|
14636
|
+
// ../../packages/db/src/schema/code-projects.ts
|
|
14637
|
+
var codeProjects;
|
|
14638
|
+
var init_code_projects = __esm({
|
|
14639
|
+
"../../packages/db/src/schema/code-projects.ts"() {
|
|
14640
|
+
"use strict";
|
|
14641
|
+
init_pg_core();
|
|
14642
|
+
init_entities();
|
|
14643
|
+
codeProjects = pgTable(
|
|
14644
|
+
"code_projects",
|
|
14645
|
+
{
|
|
14646
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
14647
|
+
entityId: uuid("entity_id").notNull().references(() => entities.id, { onDelete: "cascade" }),
|
|
14648
|
+
/** Chemin absolu slash-normalisé du projet (la clé de groupement dérivée). */
|
|
14649
|
+
projectPath: text("project_path").notNull(),
|
|
14650
|
+
/** Nom choisi par le propriétaire. NULL = nom du dossier. */
|
|
14651
|
+
displayName: text("display_name"),
|
|
14652
|
+
/** Masqué de la liste ET du contexte injecté aux agents. */
|
|
14653
|
+
hidden: boolean("hidden").notNull().default(false),
|
|
14654
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
14655
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
14656
|
+
},
|
|
14657
|
+
(table) => [
|
|
14658
|
+
unique("code_projects_entity_path_unique").on(table.entityId, table.projectPath),
|
|
14659
|
+
index("idx_code_projects_entity").on(table.entityId)
|
|
14660
|
+
]
|
|
14661
|
+
);
|
|
14662
|
+
}
|
|
14663
|
+
});
|
|
14664
|
+
|
|
14624
14665
|
// ../../packages/db/src/schema/auth.ts
|
|
14625
14666
|
var sessions, accounts, verifications;
|
|
14626
14667
|
var init_auth = __esm({
|
|
@@ -14718,6 +14759,28 @@ var init_agent_workspaces = __esm({
|
|
|
14718
14759
|
path: text("path").notNull(),
|
|
14719
14760
|
// UI display order; lower = appears first. Default 0.
|
|
14720
14761
|
position: integer("position").default(0).notNull(),
|
|
14762
|
+
/**
|
|
14763
|
+
* Ticked by the owner: "nothing written here is a project of mine."
|
|
14764
|
+
*
|
|
14765
|
+
* NOT the return of `is_dev_folder` (0085, dropped by 0086). That one asked
|
|
14766
|
+
* which folders to INCLUDE, so nothing showed until you ticked, a folder
|
|
14767
|
+
* you forgot lost real work in silence, and you still had to guess whether
|
|
14768
|
+
* the ticked folder WAS a project or CONTAINED projects.
|
|
14769
|
+
*
|
|
14770
|
+
* This one only ever removes, and it removes a whole subtree — so the
|
|
14771
|
+
* "is it a project?" question never arises. Everything shows by default,
|
|
14772
|
+
* which keeps the honest failure mode: visible noise you clear, rather than
|
|
14773
|
+
* missing work nothing tells you about. See 0087.
|
|
14774
|
+
*
|
|
14775
|
+
* The folder stays a full workspace: the agent reads and writes there as
|
|
14776
|
+
* before, and its LABEL is still used to resolve relative paths. Only the
|
|
14777
|
+
* project view ignores it — the Code tab and the injected `## Runtime`
|
|
14778
|
+
* block alike.
|
|
14779
|
+
*
|
|
14780
|
+
* A PATH counts as hidden when at least one of its rows is ticked: the same
|
|
14781
|
+
* folder attached to five agents is one gesture, not five.
|
|
14782
|
+
*/
|
|
14783
|
+
hiddenFromCode: boolean("hidden_from_code").default(false).notNull(),
|
|
14721
14784
|
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(),
|
|
14722
14785
|
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow()
|
|
14723
14786
|
},
|
|
@@ -15158,6 +15221,7 @@ __export(schema_exports, {
|
|
|
15158
15221
|
chatMessages: () => chatMessages,
|
|
15159
15222
|
cliRuns: () => cliRuns,
|
|
15160
15223
|
cliSessions: () => cliSessions,
|
|
15224
|
+
codeProjects: () => codeProjects,
|
|
15161
15225
|
connectors: () => connectors,
|
|
15162
15226
|
conversations: () => conversations,
|
|
15163
15227
|
credentials: () => credentials,
|
|
@@ -15198,6 +15262,7 @@ var init_schema2 = __esm({
|
|
|
15198
15262
|
init_schedules();
|
|
15199
15263
|
init_llm_keys();
|
|
15200
15264
|
init_mcp();
|
|
15265
|
+
init_code_projects();
|
|
15201
15266
|
init_auth();
|
|
15202
15267
|
init_agent_connector_assignments();
|
|
15203
15268
|
init_agent_workspaces();
|
|
@@ -16140,6 +16205,7 @@ __export(src_exports, {
|
|
|
16140
16205
|
chatMessages: () => chatMessages,
|
|
16141
16206
|
cliRuns: () => cliRuns,
|
|
16142
16207
|
cliSessions: () => cliSessions,
|
|
16208
|
+
codeProjects: () => codeProjects,
|
|
16143
16209
|
connectors: () => connectors,
|
|
16144
16210
|
conversations: () => conversations,
|
|
16145
16211
|
count: () => count,
|
|
@@ -16502,9 +16568,34 @@ var init_ports = __esm({
|
|
|
16502
16568
|
}
|
|
16503
16569
|
});
|
|
16504
16570
|
|
|
16571
|
+
// src/lib/log-rotation.ts
|
|
16572
|
+
import { existsSync as existsSync6, renameSync, rmSync, statSync } from "fs";
|
|
16573
|
+
function rotateLogIfNeeded(logFile, maxBytes = LOG_ROTATE_MAX_BYTES) {
|
|
16574
|
+
try {
|
|
16575
|
+
if (!existsSync6(logFile)) return false;
|
|
16576
|
+
if (statSync(logFile).size < maxBytes) return false;
|
|
16577
|
+
const archived = `${logFile}.1`;
|
|
16578
|
+
rmSync(archived, { force: true });
|
|
16579
|
+
renameSync(logFile, archived);
|
|
16580
|
+
return true;
|
|
16581
|
+
} catch (err) {
|
|
16582
|
+
console.warn(
|
|
16583
|
+
`[nodalai] log rotation skipped for ${logFile}: ${err instanceof Error ? err.message : String(err)}`
|
|
16584
|
+
);
|
|
16585
|
+
return false;
|
|
16586
|
+
}
|
|
16587
|
+
}
|
|
16588
|
+
var LOG_ROTATE_MAX_BYTES;
|
|
16589
|
+
var init_log_rotation = __esm({
|
|
16590
|
+
"src/lib/log-rotation.ts"() {
|
|
16591
|
+
"use strict";
|
|
16592
|
+
LOG_ROTATE_MAX_BYTES = 20 * 1024 * 1024;
|
|
16593
|
+
}
|
|
16594
|
+
});
|
|
16595
|
+
|
|
16505
16596
|
// src/lib/processes.ts
|
|
16506
16597
|
import { execa as execa2 } from "execa";
|
|
16507
|
-
import { createWriteStream, openSync, writeFileSync as writeFileSync4, readFileSync as readFileSync5, existsSync as
|
|
16598
|
+
import { createWriteStream, openSync, writeFileSync as writeFileSync4, readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
|
|
16508
16599
|
import { join as join6, dirname as dirname4, resolve } from "path";
|
|
16509
16600
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
16510
16601
|
async function killProcessTree(child) {
|
|
@@ -16653,7 +16744,7 @@ function resolveAppDir(appName) {
|
|
|
16653
16744
|
const fileDir = dirname4(here);
|
|
16654
16745
|
let cursor = fileDir;
|
|
16655
16746
|
for (let i = 0; i < 8; i++) {
|
|
16656
|
-
if (
|
|
16747
|
+
if (existsSync7(join6(cursor, "pnpm-workspace.yaml"))) {
|
|
16657
16748
|
return join6(cursor, appName);
|
|
16658
16749
|
}
|
|
16659
16750
|
const parent = dirname4(cursor);
|
|
@@ -16672,6 +16763,7 @@ function spawnWiring(logFile, detach) {
|
|
|
16672
16763
|
}
|
|
16673
16764
|
function spawnRunner(env, opts = {}) {
|
|
16674
16765
|
const logFile = join6(LOG_DIR, "runner.log");
|
|
16766
|
+
rotateLogIfNeeded(logFile);
|
|
16675
16767
|
const outStream = createWriteStream(logFile, { flags: "a" });
|
|
16676
16768
|
let bin;
|
|
16677
16769
|
let args;
|
|
@@ -16717,6 +16809,7 @@ env keys: ${Object.keys(env).join(",")}
|
|
|
16717
16809
|
}
|
|
16718
16810
|
function spawnWeb(env, opts = {}) {
|
|
16719
16811
|
const logFile = join6(LOG_DIR, "web.log");
|
|
16812
|
+
rotateLogIfNeeded(logFile);
|
|
16720
16813
|
const outStream = createWriteStream(logFile, { flags: "a" });
|
|
16721
16814
|
let bin;
|
|
16722
16815
|
let args;
|
|
@@ -16804,7 +16897,7 @@ function writePids(pids) {
|
|
|
16804
16897
|
}
|
|
16805
16898
|
function readPids() {
|
|
16806
16899
|
const pidFile = join6(PID_DIR, "processes.json");
|
|
16807
|
-
if (!
|
|
16900
|
+
if (!existsSync7(pidFile)) return null;
|
|
16808
16901
|
try {
|
|
16809
16902
|
return JSON.parse(readFileSync5(pidFile, "utf-8"));
|
|
16810
16903
|
} catch {
|
|
@@ -16813,7 +16906,7 @@ function readPids() {
|
|
|
16813
16906
|
}
|
|
16814
16907
|
function clearPids() {
|
|
16815
16908
|
const pidFile = join6(PID_DIR, "processes.json");
|
|
16816
|
-
if (
|
|
16909
|
+
if (existsSync7(pidFile)) {
|
|
16817
16910
|
writeFileSync4(pidFile, JSON.stringify({}), "utf-8");
|
|
16818
16911
|
}
|
|
16819
16912
|
}
|
|
@@ -16859,6 +16952,7 @@ var init_processes = __esm({
|
|
|
16859
16952
|
"src/lib/processes.ts"() {
|
|
16860
16953
|
"use strict";
|
|
16861
16954
|
init_config();
|
|
16955
|
+
init_log_rotation();
|
|
16862
16956
|
SNAPSHOT_BUDGET_MS = 2e4;
|
|
16863
16957
|
SHUTDOWN_SNAPSHOT_BUDGET_MS = 6e3;
|
|
16864
16958
|
inFlightSnapshot = null;
|
|
@@ -16890,11 +16984,76 @@ var init_processes = __esm({
|
|
|
16890
16984
|
lastSnapshotFailure = null;
|
|
16891
16985
|
BUNDLED_ROOT = (() => {
|
|
16892
16986
|
const here = dirname4(fileURLToPath3(import.meta.url));
|
|
16893
|
-
return
|
|
16987
|
+
return existsSync7(join6(here, "runner.js")) ? here : null;
|
|
16894
16988
|
})();
|
|
16895
16989
|
}
|
|
16896
16990
|
});
|
|
16897
16991
|
|
|
16992
|
+
// src/lib/watchdog.ts
|
|
16993
|
+
async function probeRunnerHealth(runnerUrl) {
|
|
16994
|
+
try {
|
|
16995
|
+
const controller = new AbortController();
|
|
16996
|
+
const t = setTimeout(() => controller.abort(), 3e3);
|
|
16997
|
+
const res = await fetch(`${runnerUrl}/api/health`, { signal: controller.signal });
|
|
16998
|
+
clearTimeout(t);
|
|
16999
|
+
if (res.status === 200) return { state: "healthy", detail: "" };
|
|
17000
|
+
const body = await res.json().catch(() => null);
|
|
17001
|
+
const detail = body?.db === "error" ? "database unreachable (runner reports db: error)" : `runner is unhealthy (HTTP ${res.status})`;
|
|
17002
|
+
return { state: "degraded", detail };
|
|
17003
|
+
} catch (err) {
|
|
17004
|
+
const aborted = err instanceof Error && err.name === "AbortError";
|
|
17005
|
+
return {
|
|
17006
|
+
state: "unreachable",
|
|
17007
|
+
detail: aborted ? "runner did not answer /api/health within 3s (busy or stalled)" : "runner is not answering /api/health"
|
|
17008
|
+
};
|
|
17009
|
+
}
|
|
17010
|
+
}
|
|
17011
|
+
function startHealthWatchdog(opts) {
|
|
17012
|
+
const intervalMs = opts.intervalMs ?? 3e4;
|
|
17013
|
+
const failureThreshold = opts.failureThreshold ?? 2;
|
|
17014
|
+
let announced = "healthy";
|
|
17015
|
+
let consecutiveFailures = 0;
|
|
17016
|
+
let stopped = false;
|
|
17017
|
+
let inFlight = false;
|
|
17018
|
+
const tick = async () => {
|
|
17019
|
+
if (stopped || inFlight) return;
|
|
17020
|
+
inFlight = true;
|
|
17021
|
+
try {
|
|
17022
|
+
const result = await opts.probe();
|
|
17023
|
+
if (stopped) return;
|
|
17024
|
+
if (result.state === "healthy") {
|
|
17025
|
+
consecutiveFailures = 0;
|
|
17026
|
+
if (announced !== "healthy") {
|
|
17027
|
+
announced = "healthy";
|
|
17028
|
+
opts.onTransition("healthy", "services are answering again");
|
|
17029
|
+
}
|
|
17030
|
+
return;
|
|
17031
|
+
}
|
|
17032
|
+
consecutiveFailures += 1;
|
|
17033
|
+
if (consecutiveFailures < failureThreshold) return;
|
|
17034
|
+
if (announced !== result.state) {
|
|
17035
|
+
announced = result.state;
|
|
17036
|
+
opts.onTransition(result.state, result.detail);
|
|
17037
|
+
}
|
|
17038
|
+
} finally {
|
|
17039
|
+
inFlight = false;
|
|
17040
|
+
}
|
|
17041
|
+
};
|
|
17042
|
+
const timer2 = setInterval(() => void tick(), intervalMs);
|
|
17043
|
+
timer2.unref?.();
|
|
17044
|
+
return {
|
|
17045
|
+
stop: () => {
|
|
17046
|
+
stopped = true;
|
|
17047
|
+
clearInterval(timer2);
|
|
17048
|
+
}
|
|
17049
|
+
};
|
|
17050
|
+
}
|
|
17051
|
+
var init_watchdog = __esm({
|
|
17052
|
+
"src/lib/watchdog.ts"() {
|
|
17053
|
+
"use strict";
|
|
17054
|
+
}
|
|
17055
|
+
});
|
|
17056
|
+
|
|
16898
17057
|
// src/commands/up.ts
|
|
16899
17058
|
var up_exports = {};
|
|
16900
17059
|
__export(up_exports, {
|
|
@@ -16904,7 +17063,7 @@ import chalk from "chalk";
|
|
|
16904
17063
|
import ora from "ora";
|
|
16905
17064
|
import open from "open";
|
|
16906
17065
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
16907
|
-
import { existsSync as
|
|
17066
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
16908
17067
|
import { join as join7 } from "path";
|
|
16909
17068
|
async function killSilent(child) {
|
|
16910
17069
|
await killProcessTree(child);
|
|
@@ -16912,7 +17071,7 @@ async function killSilent(child) {
|
|
|
16912
17071
|
function printLogTail(service, lines) {
|
|
16913
17072
|
const logFile = join7(LOG_DIR, `${service}.log`);
|
|
16914
17073
|
try {
|
|
16915
|
-
if (!
|
|
17074
|
+
if (!existsSync8(logFile)) {
|
|
16916
17075
|
console.error(chalk.gray(`
|
|
16917
17076
|
${service}: no log at ${logFile}`));
|
|
16918
17077
|
return;
|
|
@@ -17274,7 +17433,32 @@ ${lines}
|
|
|
17274
17433
|
}
|
|
17275
17434
|
console.log(chalk.gray(" Ctrl+C to stop all services"));
|
|
17276
17435
|
console.log("");
|
|
17436
|
+
const watchdog = startHealthWatchdog({
|
|
17437
|
+
probe: () => probeRunnerHealth(runnerUrl),
|
|
17438
|
+
onTransition: (state, detail) => {
|
|
17439
|
+
const at = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
17440
|
+
if (state === "healthy") {
|
|
17441
|
+
console.log(chalk.green(`
|
|
17442
|
+
[${at}] Recovered \u2014 ${detail}.`));
|
|
17443
|
+
return;
|
|
17444
|
+
}
|
|
17445
|
+
console.error(chalk.red.bold(`
|
|
17446
|
+
[${at}] DEGRADED \u2014 ${detail}.`));
|
|
17447
|
+
if (state === "degraded") {
|
|
17448
|
+
console.error(
|
|
17449
|
+
chalk.red(
|
|
17450
|
+
" The dashboard may still render, but nothing can read or write the database:\n jobs are not created, chats and schedules are failing."
|
|
17451
|
+
)
|
|
17452
|
+
);
|
|
17453
|
+
printLogTail("runner", 10);
|
|
17454
|
+
}
|
|
17455
|
+
console.error(
|
|
17456
|
+
chalk.yellow(" \u2192 Restart the stack: `nodal-agents down`, then `nodal-agents up`.")
|
|
17457
|
+
);
|
|
17458
|
+
}
|
|
17459
|
+
});
|
|
17277
17460
|
await Promise.race([runnerProcess, webProcess]);
|
|
17461
|
+
watchdog.stop();
|
|
17278
17462
|
await shutdown();
|
|
17279
17463
|
}
|
|
17280
17464
|
var init_up = __esm({
|
|
@@ -17287,6 +17471,7 @@ var init_up = __esm({
|
|
|
17287
17471
|
init_ports();
|
|
17288
17472
|
init_processes();
|
|
17289
17473
|
init_src4();
|
|
17474
|
+
init_watchdog();
|
|
17290
17475
|
}
|
|
17291
17476
|
});
|
|
17292
17477
|
|
|
@@ -17574,7 +17759,7 @@ __export(down_exports, {
|
|
|
17574
17759
|
runDown: () => runDown
|
|
17575
17760
|
});
|
|
17576
17761
|
import chalk3 from "chalk";
|
|
17577
|
-
import { existsSync as
|
|
17762
|
+
import { existsSync as existsSync9 } from "fs";
|
|
17578
17763
|
import { join as join8 } from "path";
|
|
17579
17764
|
async function killPid(pid, label) {
|
|
17580
17765
|
if (!isPidAlive(pid)) {
|
|
@@ -17591,7 +17776,7 @@ async function killPid(pid, label) {
|
|
|
17591
17776
|
}
|
|
17592
17777
|
async function stopPostgresGracefully() {
|
|
17593
17778
|
const pidFile = join8(PG_DATA_DIR, "postmaster.pid");
|
|
17594
|
-
if (!
|
|
17779
|
+
if (!existsSync9(pidFile)) return false;
|
|
17595
17780
|
const pgPid = readPostmasterPid(PG_DATA_DIR);
|
|
17596
17781
|
try {
|
|
17597
17782
|
const EmbeddedPostgres = (await import("embedded-postgres")).default;
|
|
@@ -17661,7 +17846,7 @@ __export(logs_exports, {
|
|
|
17661
17846
|
runLogs: () => runLogs
|
|
17662
17847
|
});
|
|
17663
17848
|
import chalk4 from "chalk";
|
|
17664
|
-
import { existsSync as
|
|
17849
|
+
import { existsSync as existsSync10, createReadStream, watch, statSync as statSync2 } from "fs";
|
|
17665
17850
|
import { join as join9 } from "path";
|
|
17666
17851
|
function isServiceName(s) {
|
|
17667
17852
|
return VALID_SERVICES.includes(s);
|
|
@@ -17675,7 +17860,7 @@ async function runLogs(service) {
|
|
|
17675
17860
|
const services = target === "all" ? VALID_SERVICES : [target];
|
|
17676
17861
|
for (const svc of services) {
|
|
17677
17862
|
const logFile = join9(LOG_DIR, `${svc}.log`);
|
|
17678
|
-
if (!
|
|
17863
|
+
if (!existsSync10(logFile)) {
|
|
17679
17864
|
console.log(chalk4.gray(` [${svc}] No log file yet at ${logFile}`));
|
|
17680
17865
|
continue;
|
|
17681
17866
|
}
|
|
@@ -17690,18 +17875,18 @@ async function runLogs(service) {
|
|
|
17690
17875
|
}
|
|
17691
17876
|
if (target !== "all") {
|
|
17692
17877
|
const logFile = join9(LOG_DIR, `${target}.log`);
|
|
17693
|
-
if (!
|
|
17878
|
+
if (!existsSync10(logFile)) {
|
|
17694
17879
|
console.log(chalk4.yellow("Waiting for log file to be created\u2026"));
|
|
17695
17880
|
}
|
|
17696
17881
|
console.log(chalk4.gray("\nFollowing log (Ctrl+C to stop)...\n"));
|
|
17697
17882
|
let fileSize = 0;
|
|
17698
17883
|
try {
|
|
17699
|
-
fileSize =
|
|
17884
|
+
fileSize = statSync2(logFile).size;
|
|
17700
17885
|
} catch {
|
|
17701
17886
|
}
|
|
17702
17887
|
const watcher = watch(logFile, () => {
|
|
17703
17888
|
try {
|
|
17704
|
-
const newSize =
|
|
17889
|
+
const newSize = statSync2(logFile).size;
|
|
17705
17890
|
if (newSize > fileSize) {
|
|
17706
17891
|
const stream = createReadStream(logFile, { start: fileSize, encoding: "utf-8" });
|
|
17707
17892
|
stream.on("data", (chunk) => process.stdout.write(chunk));
|
|
@@ -17728,7 +17913,7 @@ var init_logs = __esm({
|
|
|
17728
17913
|
import { execFile } from "child_process";
|
|
17729
17914
|
import { createHash as createHash2 } from "crypto";
|
|
17730
17915
|
import { mkdir, writeFile } from "fs/promises";
|
|
17731
|
-
import { existsSync as
|
|
17916
|
+
import { existsSync as existsSync11 } from "fs";
|
|
17732
17917
|
import { join as join10 } from "path";
|
|
17733
17918
|
import { promisify } from "util";
|
|
17734
17919
|
function workspaceKey(workspace) {
|
|
@@ -17768,7 +17953,7 @@ async function ensureStore(store) {
|
|
|
17768
17953
|
const gitDir = join10(store, "store");
|
|
17769
17954
|
await mkdir(join10(store, "indexes"), { recursive: true });
|
|
17770
17955
|
await writeFile(join10(store, "gitconfig"), "", { flag: "a" });
|
|
17771
|
-
if (!
|
|
17956
|
+
if (!existsSync11(join10(gitDir, "HEAD"))) {
|
|
17772
17957
|
await mkdir(gitDir, { recursive: true });
|
|
17773
17958
|
await run("git", ["init", "--bare", "--quiet", gitDir], {
|
|
17774
17959
|
timeout: GIT_TIMEOUT_MS,
|
|
@@ -17801,7 +17986,7 @@ async function snapshot(store, workspace, label) {
|
|
|
17801
17986
|
return { sha, workspace, at, label };
|
|
17802
17987
|
}
|
|
17803
17988
|
async function listCheckpoints(store, workspace, limit = 20) {
|
|
17804
|
-
if (!
|
|
17989
|
+
if (!existsSync11(join10(store, "store", "HEAD"))) return [];
|
|
17805
17990
|
const ref = `refs/nodal/${workspaceKey(workspace)}`;
|
|
17806
17991
|
const out = await git(store, workspace, [
|
|
17807
17992
|
"log",
|
|
@@ -30975,7 +31160,13 @@ async function buildNodalMcpServer(opts) {
|
|
|
30975
31160
|
}
|
|
30976
31161
|
targetAgent = root;
|
|
30977
31162
|
} else {
|
|
30978
|
-
const [launcher] = await opts.db.select({ id: agents.id }).from(agents).where(
|
|
31163
|
+
const [launcher] = await opts.db.select({ id: agents.id }).from(agents).where(
|
|
31164
|
+
and(
|
|
31165
|
+
eq(agents.id, agentRow.id),
|
|
31166
|
+
eq(agents.active, true),
|
|
31167
|
+
eq(agents.entityId, entityId)
|
|
31168
|
+
)
|
|
31169
|
+
).limit(1);
|
|
30979
31170
|
if (!launcher) {
|
|
30980
31171
|
throw new Error(
|
|
30981
31172
|
"mcp_agent_not_found: the agent this server was launched for has been deactivated. Reactivate it, set a root agent, or restart the server for another agent."
|
|
@@ -31185,7 +31376,7 @@ __export(reset_exports, {
|
|
|
31185
31376
|
});
|
|
31186
31377
|
import chalk6 from "chalk";
|
|
31187
31378
|
import prompts2 from "prompts";
|
|
31188
|
-
import { rmSync, existsSync as
|
|
31379
|
+
import { rmSync as rmSync2, existsSync as existsSync12 } from "fs";
|
|
31189
31380
|
async function runReset(options = {}) {
|
|
31190
31381
|
if (!options.yes) {
|
|
31191
31382
|
const { confirm } = await prompts2({
|
|
@@ -31203,8 +31394,8 @@ async function runReset(options = {}) {
|
|
|
31203
31394
|
}
|
|
31204
31395
|
console.log(chalk6.yellow("Stopping any running processes\u2026"));
|
|
31205
31396
|
await runDown();
|
|
31206
|
-
if (
|
|
31207
|
-
|
|
31397
|
+
if (existsSync12(CONFIG_DIR)) {
|
|
31398
|
+
rmSync2(CONFIG_DIR, { recursive: true, force: true });
|
|
31208
31399
|
console.log(chalk6.green(` Removed ${CONFIG_DIR}`));
|
|
31209
31400
|
} else {
|
|
31210
31401
|
console.log(chalk6.gray(` ${CONFIG_DIR} was already empty`));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- 0082 — inversion du modele a deux cles Yolo (decision Quentin 24/08).
|
|
2
|
+
--
|
|
3
|
+
-- L'ancien lan_command_yolo etait une PRE-CONDITION : sur une install reseau,
|
|
4
|
+
-- il fallait l'allumer pour avoir LE DROIT d'activer le Yolo par agent — deux
|
|
5
|
+
-- serrures, une seule cle (les deux gestes etaient deja owner-only). Sa vraie
|
|
6
|
+
-- valeur etait le coupe-circuit : l'eteindre rendait dormantes toutes les
|
|
7
|
+
-- regles d'un coup. auto_run_paused ne garde QUE ce role : un frein
|
|
8
|
+
-- d'urgence, inactif par defaut, qui met en pause tout l'auto-run de code du
|
|
9
|
+
-- workspace quand on l'enclenche.
|
|
10
|
+
--
|
|
11
|
+
-- Le backfill preserve l'INTENTION de chaque install : un master OFF alors
|
|
12
|
+
-- que des regles auto_approve d'outils d'execution existent = le proprietaire
|
|
13
|
+
-- avait deliberement coupe (usage coupe-circuit) -> pause maintenue. Un
|
|
14
|
+
-- master OFF sans aucune regle armee (l'immense majorite, dont toute install
|
|
15
|
+
-- neuve) = rien a couper -> pas de pause. Un master ON = il autorisait ->
|
|
16
|
+
-- pas de pause. Aucun comportement effectif ne change au reboot.
|
|
17
|
+
ALTER TABLE entities ADD COLUMN auto_run_paused boolean NOT NULL DEFAULT false;
|
|
18
|
+
|
|
19
|
+
UPDATE entities e
|
|
20
|
+
SET auto_run_paused = true
|
|
21
|
+
WHERE e.lan_command_yolo = false
|
|
22
|
+
AND EXISTS (
|
|
23
|
+
SELECT 1
|
|
24
|
+
FROM approval_rules ar
|
|
25
|
+
LEFT JOIN agents a ON a.id = ar.agent_id
|
|
26
|
+
WHERE ar.action = 'auto_approve'
|
|
27
|
+
AND ar.tool_name IN ('run_command', 'code_task', 'run_skill_script',
|
|
28
|
+
'skill_file_write', 'create_mcp', 'attach_mcp')
|
|
29
|
+
AND (a.entity_id = e.id OR ar.entity_id = e.id)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
ALTER TABLE entities DROP COLUMN lan_command_yolo;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- 0083 — archives de projets de l'onglet Code (décision Quentin 25/08).
|
|
2
|
+
-- Un « projet » est DÉRIVÉ à l'affichage (racine git / workspace des fichiers
|
|
3
|
+
-- touchés) — il n'existe pas en base. L'archivage, lui, est un état UI qui
|
|
4
|
+
-- doit survivre : une ligne par (workspace, chemin de projet) archivé.
|
|
5
|
+
-- AUCUN effet sur le dossier réel — désarchiver = supprimer la ligne.
|
|
6
|
+
CREATE TABLE IF NOT EXISTS "code_project_archives" (
|
|
7
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
8
|
+
"entity_id" uuid NOT NULL REFERENCES "entities"("id") ON DELETE CASCADE,
|
|
9
|
+
"project_path" text NOT NULL,
|
|
10
|
+
"archived_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
11
|
+
CONSTRAINT "code_project_archives_entity_path_unique" UNIQUE ("entity_id", "project_path")
|
|
12
|
+
);
|
|
13
|
+
--> statement-breakpoint
|
|
14
|
+
CREATE INDEX IF NOT EXISTS "idx_code_project_archives_entity" ON "code_project_archives" ("entity_id");
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- 0084 — annule le backfill fautif de 0082 (revue P0 du 25/08, finding bloquant).
|
|
2
|
+
--
|
|
3
|
+
-- Le backfill de 0082 posait `auto_run_paused = true` quand l'ancien
|
|
4
|
+
-- `lan_command_yolo` valait false ET qu'une regle auto_approve d'outil de code
|
|
5
|
+
-- existait, en lisant ce false comme « le proprietaire avait deliberement
|
|
6
|
+
-- coupe ». La premisse est FAUSSE sur le mode par defaut : hors LAN
|
|
7
|
+
-- (local-trust), l'ancienne garde ne s'appliquait pas du tout et la section
|
|
8
|
+
-- Settings etait masquee — le drapeau y valait false par construction, sans
|
|
9
|
+
-- jamais avoir rien voulu dire. Consequence : une install locale qui avait
|
|
10
|
+
-- active un Yolo se retrouvait, apres mise a jour, avec ses crons et ses
|
|
11
|
+
-- taches Telegram suspendus en attente d'approbation, sans qu'aucun geste
|
|
12
|
+
-- n'ait ete fait.
|
|
13
|
+
--
|
|
14
|
+
-- Le frein est un GESTE DELIBERE, pas un etat devine : il repart relache
|
|
15
|
+
-- partout (sa valeur par defaut), et quiconque le veut l'enclenche en un clic
|
|
16
|
+
-- dans Settings. La fenetre concernee est courte (0082 date du 24/08) et
|
|
17
|
+
-- l'etat est visible dans l'interface, donc la correction ne peut pas
|
|
18
|
+
-- surprendre en silence.
|
|
19
|
+
--
|
|
20
|
+
-- Le durcissement qui compte vit ailleurs, dans le code : l'autonomie du
|
|
21
|
+
-- workspace ne relaxe plus JAMAIS les outils d'execution de code
|
|
22
|
+
-- (packages/tools/src/execute.ts, isCodeExecutionTool) — seule une regle
|
|
23
|
+
-- explicite par agent le fait.
|
|
24
|
+
UPDATE entities SET auto_run_paused = false WHERE auto_run_paused = true;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- 0085 — un dossier de developpement se COCHE, il ne se devine pas.
|
|
2
|
+
--
|
|
3
|
+
-- L'onglet Code doit montrer le travail de developpement, et rien d'autre.
|
|
4
|
+
-- Quatre definitions ont ete essayees et ecartees, toutes parce qu'elles
|
|
5
|
+
-- DEVINAIENT :
|
|
6
|
+
--
|
|
7
|
+
-- * la nature des fichiers edites (extensions) : « une exclusion par langage
|
|
8
|
+
-- ratera tot ou tard du vrai code » — un .json de mock-data EST du code.
|
|
9
|
+
-- Et le coffre Obsidian qualifiait quand meme, a cause de vrais .py ecrits
|
|
10
|
+
-- dedans en juillet ;
|
|
11
|
+
-- * le skill porte par l'agent : ne marche que si l'utilisateur emploie NOS
|
|
12
|
+
-- skills, jamais les siens ni ceux du catalogue communautaire ;
|
|
13
|
+
-- * la structure du dossier (package.json, .git…) : symetrique du premier
|
|
14
|
+
-- echec — « on va 100 % avoir des faux positifs », un depot clone ou un
|
|
15
|
+
-- theme jamais touche en porte un ;
|
|
16
|
+
-- * une case sur l'AGENT : repond au « qui », pas au « ou ». Un agent qui
|
|
17
|
+
-- code le matin et range le coffre l'apres-midi y ferait entrer le coffre.
|
|
18
|
+
--
|
|
19
|
+
-- D'ou cette colonne : la designation porte sur le DOSSIER, et elle est
|
|
20
|
+
-- explicite. La case definit un PERIMETRE, pas un projet — cocher `Dev` ne
|
|
21
|
+
-- fait pas de `Dev` un projet, ses sous-dossiers en sont.
|
|
22
|
+
--
|
|
23
|
+
-- Aucun backfill : cocher un dossier a la place du proprietaire serait une
|
|
24
|
+
-- devinette de plus, exactement ce que ce lot supprime. L'onglet Code nomme le
|
|
25
|
+
-- geste tant qu'aucun dossier n'est coche.
|
|
26
|
+
ALTER TABLE agent_workspaces
|
|
27
|
+
ADD COLUMN IF NOT EXISTS is_dev_folder boolean NOT NULL DEFAULT false;
|
|
28
|
+
--> statement-breakpoint
|
|
29
|
+
-- La derivation des projets lit les dossiers coches a chaque job et a chaque
|
|
30
|
+
-- chargement de l'onglet : un index partiel garde ces lectures triviales.
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_agent_workspaces_dev_folder
|
|
32
|
+
ON agent_workspaces (entity_id)
|
|
33
|
+
WHERE is_dev_folder;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
-- 0086 — l'onglet Code cesse de DEVINER, et l'utilisateur reprend la main.
|
|
2
|
+
--
|
|
3
|
+
-- Six definitions ont ete essayees pour savoir ce qui merite d'apparaitre dans
|
|
4
|
+
-- l'onglet Code. Toutes ecartees, toutes pour la meme raison : elles
|
|
5
|
+
-- decidaient a la place du proprietaire, sur un indice indirect.
|
|
6
|
+
--
|
|
7
|
+
-- 1. l'extension des fichiers « une exclusion par langage ratera tot
|
|
8
|
+
-- ou tard du vrai code »
|
|
9
|
+
-- 2. le skill porte par l'agent ne marche qu'avec NOS skills
|
|
10
|
+
-- 3. la structure du dossier « on va 100 % avoir des faux positifs »
|
|
11
|
+
-- 4. une case sur l'agent repond au « qui », pas au « ou »
|
|
12
|
+
-- 5. une case sur le dossier (0085) il faut encore deviner si le
|
|
13
|
+
-- dossier coche EST un projet ou en
|
|
14
|
+
-- CONTIENT
|
|
15
|
+
-- 6. une nature devinee par dossier liste sans fin : Obsidian, ComfyUI,
|
|
16
|
+
-- Blender, Unity, Godot, un CMS…
|
|
17
|
+
--
|
|
18
|
+
-- Decision Quentin (26/08) : ne rien deviner. L'onglet montre les dossiers ou
|
|
19
|
+
-- les agents ont travaille, et le proprietaire dispose des deux seuls gestes
|
|
20
|
+
-- que le produit ne peut pas poser a sa place : RENOMMER ce qui porte mal son
|
|
21
|
+
-- nom, MASQUER ce qu'il ne veut plus voir.
|
|
22
|
+
--
|
|
23
|
+
-- D'ou cette migration :
|
|
24
|
+
-- * `agent_workspaces.is_dev_folder` disparait — le filtrage n'existe plus ;
|
|
25
|
+
-- * `code_project_archives` devient `code_projects`, qui porte desormais les
|
|
26
|
+
-- DEUX gestes au lieu du seul masquage.
|
|
27
|
+
--
|
|
28
|
+
-- « Masquer » plutot qu'« archiver » : le dossier n'est jamais touche, rien
|
|
29
|
+
-- n'est fini ni range definitivement — c'est un choix d'affichage, et le mot
|
|
30
|
+
-- doit le dire. Le masquage retire aussi le projet du contexte injecte aux
|
|
31
|
+
-- agents, ce que l'archivage ne faisait pas : un projet range n'a pas a etre
|
|
32
|
+
-- annonce dans le prompt de tout le monde.
|
|
33
|
+
ALTER TABLE agent_workspaces DROP COLUMN IF EXISTS is_dev_folder;
|
|
34
|
+
--> statement-breakpoint
|
|
35
|
+
CREATE TABLE IF NOT EXISTS code_projects (
|
|
36
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
37
|
+
entity_id uuid NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
|
|
38
|
+
-- Chemin absolu du projet, slash-normalise (la forme que rend la derivation).
|
|
39
|
+
project_path text NOT NULL,
|
|
40
|
+
-- Nom choisi par le proprietaire. NULL = on affiche le nom du dossier.
|
|
41
|
+
display_name text,
|
|
42
|
+
-- Masque de la liste ET du contexte des agents.
|
|
43
|
+
hidden boolean NOT NULL DEFAULT false,
|
|
44
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
45
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
46
|
+
UNIQUE (entity_id, project_path)
|
|
47
|
+
);
|
|
48
|
+
--> statement-breakpoint
|
|
49
|
+
-- Les projets deja archives restent masques : le geste avait ete pose, il est
|
|
50
|
+
-- conserve tel quel.
|
|
51
|
+
INSERT INTO code_projects (entity_id, project_path, hidden, created_at)
|
|
52
|
+
SELECT entity_id, project_path, true, archived_at
|
|
53
|
+
FROM code_project_archives
|
|
54
|
+
ON CONFLICT (entity_id, project_path) DO NOTHING;
|
|
55
|
+
--> statement-breakpoint
|
|
56
|
+
DROP TABLE IF EXISTS code_project_archives;
|
|
57
|
+
--> statement-breakpoint
|
|
58
|
+
-- La liste est lue a chaque chargement de l'onglet ET a chaque job (le contexte
|
|
59
|
+
-- des agents doit savoir ce qui est masque) : l'index garde ces lectures
|
|
60
|
+
-- triviales.
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_code_projects_entity ON code_projects (entity_id);
|