@notis_ai/cli 0.2.13 → 0.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -21
- package/dist/agent-hooks/notis-agent-hook.mjs +19750 -0
- package/{skills → dist/base-skills}/notis-apps/SKILL.md +93 -58
- package/{skills → dist/base-skills}/notis-cli/SKILL.md +9 -9
- package/dist/base-skills/notis-query/SKILL.md +705 -0
- package/dist/skill-sync/index.js +1528 -0
- package/dist/skill-sync/index.js.map +7 -0
- package/package.json +5 -2
- package/skills/notis-apps/cli.md +44 -18
- package/skills/notis-cli/AGENT_INSTRUCTIONS.md +39 -0
- package/skills/notis-onboarding/BRIEF.md +16 -0
- package/src/agent-hook-entry.js +5 -0
- package/src/cli.js +23 -14
- package/src/command-specs/agents.js +392 -0
- package/src/command-specs/apps.js +1090 -418
- package/src/command-specs/auth.js +63 -10
- package/src/command-specs/handover.js +374 -0
- package/src/command-specs/index.js +9 -0
- package/src/command-specs/onboarding.js +69 -5
- package/src/command-specs/skills.js +56 -0
- package/src/command-specs/tools.js +6 -0
- package/src/runtime/agent-memory-state.js +126 -0
- package/src/runtime/agent-setup.js +383 -0
- package/src/runtime/app-dev-consumers.js +154 -0
- package/src/runtime/app-dev-host-lock.js +80 -0
- package/src/runtime/app-dev-roots.js +284 -0
- package/src/runtime/app-dev-server.js +229 -30
- package/src/runtime/app-dev-sessions.js +105 -145
- package/src/runtime/app-platform.js +1499 -161
- package/src/runtime/app-registry-scaffolds.js +367 -0
- package/src/runtime/base-skills.d.ts +20 -0
- package/src/runtime/base-skills.js +167 -0
- package/src/runtime/delegated-context.js +68 -0
- package/src/runtime/git.js +233 -0
- package/src/runtime/login-listener.js +15 -0
- package/src/runtime/oauth.js +1506 -141
- package/src/runtime/output.js +7 -0
- package/src/runtime/ports.js +16 -0
- package/src/runtime/profiles.js +0 -5
- package/src/runtime/skill-sync/cloud-client.ts +96 -0
- package/src/runtime/skill-sync/index.ts +644 -0
- package/src/runtime/skill-sync/local-scanner.ts +1046 -0
- package/src/runtime/skill-sync/symlink-manager.ts +383 -0
- package/src/runtime/skill-sync/sync-plan.ts +22 -0
- package/src/runtime/skill-sync/types.ts +103 -0
- package/src/runtime/skill-sync/write-cloud-skill.ts +50 -0
- package/src/runtime/store-screenshot.js +6 -1
- package/src/runtime/sync-skills.d.ts +37 -0
- package/src/runtime/sync-skills.js +215 -0
- package/src/runtime/transport.js +19 -2
- package/template/.harness/index.html.tmpl +116 -47
- package/template/app/layout.tsx +5 -1
- package/template/notis.config.ts +1 -0
- package/template/packages/sdk/package.json +2 -1
- package/template/packages/sdk/src/components/DocumentEditor.tsx +13 -3
- package/template/packages/sdk/src/components/MarkdownEditor.tsx +121 -0
- package/template/packages/sdk/src/components/MultiSelectActionBar.tsx +37 -119
- package/template/packages/sdk/src/components/MultiSelectCheckbox.tsx +5 -1
- package/template/packages/sdk/src/components/MultiSelectDragOverlay.tsx +1 -1
- package/template/packages/sdk/src/components/NotisSelectionBoundary.tsx +55 -0
- package/template/packages/sdk/src/components/ShortcutHints.tsx +56 -0
- package/template/packages/sdk/src/config.ts +71 -0
- package/template/packages/sdk/src/documents.ts +28 -1
- package/template/packages/sdk/src/hooks/useActiveResource.ts +19 -0
- package/template/packages/sdk/src/hooks/useCloudComputer.ts +97 -0
- package/template/packages/sdk/src/hooks/useCollectionInteractions.ts +709 -0
- package/template/packages/sdk/src/hooks/useDatabaseSubscription.ts +76 -0
- package/template/packages/sdk/src/hooks/useHandover.ts +78 -0
- package/template/packages/sdk/src/hooks/useMultiSelect.ts +44 -482
- package/template/packages/sdk/src/hooks/useTool.ts +5 -4
- package/template/packages/sdk/src/index.ts +64 -2
- package/template/packages/sdk/src/interactions/actions.ts +46 -0
- package/template/packages/sdk/src/interactions/shortcuts.tsx +628 -0
- package/template/packages/sdk/src/interactions.ts +41 -0
- package/template/packages/sdk/src/provider.tsx +2 -1
- package/template/packages/sdk/src/runtime.ts +219 -3
- package/dist/scaffolds/notis-database/CHANGELOG.md +0 -5
- package/dist/scaffolds/notis-database/app/globals.css +0 -44
- package/dist/scaffolds/notis-database/app/layout.tsx +0 -6
- package/dist/scaffolds/notis-database/app/page.tsx +0 -1088
- package/dist/scaffolds/notis-database/components/ui/badge.tsx +0 -28
- package/dist/scaffolds/notis-database/components/ui/button.tsx +0 -53
- package/dist/scaffolds/notis-database/components/ui/card.tsx +0 -56
- package/dist/scaffolds/notis-database/components/ui/table.tsx +0 -120
- package/dist/scaffolds/notis-database/components.json +0 -20
- package/dist/scaffolds/notis-database/index.html +0 -12
- package/dist/scaffolds/notis-database/lib/types.ts +0 -132
- package/dist/scaffolds/notis-database/lib/utils.ts +0 -6
- package/dist/scaffolds/notis-database/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-database/metadata/screenshot-fixtures.json +0 -1839
- package/dist/scaffolds/notis-database/notis.config.ts +0 -73
- package/dist/scaffolds/notis-database/package-lock.json +0 -3935
- package/dist/scaffolds/notis-database/package.json +0 -32
- package/dist/scaffolds/notis-database/packages/sdk/package.json +0 -36
- package/dist/scaffolds/notis-database/packages/sdk/src/components/DocumentEditor.tsx +0 -93
- package/dist/scaffolds/notis-database/packages/sdk/src/components/Markdown.tsx +0 -60
- package/dist/scaffolds/notis-database/packages/sdk/src/components/MultiSelectActionBar.tsx +0 -278
- package/dist/scaffolds/notis-database/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -91
- package/dist/scaffolds/notis-database/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -39
- package/dist/scaffolds/notis-database/packages/sdk/src/config.ts +0 -196
- package/dist/scaffolds/notis-database/packages/sdk/src/documents.ts +0 -229
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useBackend.ts +0 -41
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocument.ts +0 -78
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useDocuments.ts +0 -121
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useMultiSelect.ts +0 -539
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useNotis.ts +0 -34
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useNotisNavigation.ts +0 -49
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useTool.ts +0 -64
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useTools.ts +0 -56
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
- package/dist/scaffolds/notis-database/packages/sdk/src/hooks/useUpsertDocument.ts +0 -95
- package/dist/scaffolds/notis-database/packages/sdk/src/index.ts +0 -83
- package/dist/scaffolds/notis-database/packages/sdk/src/provider.tsx +0 -43
- package/dist/scaffolds/notis-database/packages/sdk/src/runtime.ts +0 -220
- package/dist/scaffolds/notis-database/packages/sdk/src/styles.css +0 -186
- package/dist/scaffolds/notis-database/packages/sdk/src/ui.ts +0 -15
- package/dist/scaffolds/notis-database/packages/sdk/src/vite.ts +0 -56
- package/dist/scaffolds/notis-database/packages/sdk/tsconfig.json +0 -15
- package/dist/scaffolds/notis-database/postcss.config.mjs +0 -8
- package/dist/scaffolds/notis-database/src/dev-main.tsx +0 -23
- package/dist/scaffolds/notis-database/src/mock-runtime.ts +0 -561
- package/dist/scaffolds/notis-database/tailwind.config.ts +0 -59
- package/dist/scaffolds/notis-database/tsconfig.json +0 -23
- package/dist/scaffolds/notis-database/vite.config.ts +0 -22
- package/dist/scaffolds/notis-journal/CHANGELOG.md +0 -29
- package/dist/scaffolds/notis-journal/app/globals.css +0 -37
- package/dist/scaffolds/notis-journal/app/insights/page.tsx +0 -513
- package/dist/scaffolds/notis-journal/app/journal-core.tsx +0 -362
- package/dist/scaffolds/notis-journal/app/journal-ui.tsx +0 -337
- package/dist/scaffolds/notis-journal/app/layout.tsx +0 -6
- package/dist/scaffolds/notis-journal/app/page.tsx +0 -486
- package/dist/scaffolds/notis-journal/components/ui/badge.tsx +0 -28
- package/dist/scaffolds/notis-journal/components/ui/button.tsx +0 -53
- package/dist/scaffolds/notis-journal/components/ui/card.tsx +0 -56
- package/dist/scaffolds/notis-journal/components.json +0 -20
- package/dist/scaffolds/notis-journal/index.html +0 -12
- package/dist/scaffolds/notis-journal/lib/utils.ts +0 -6
- package/dist/scaffolds/notis-journal/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-6.png +0 -0
- package/dist/scaffolds/notis-journal/metadata/screenshot-fixtures.json +0 -132
- package/dist/scaffolds/notis-journal/notis.config.ts +0 -93
- package/dist/scaffolds/notis-journal/package-lock.json +0 -4615
- package/dist/scaffolds/notis-journal/package.json +0 -34
- package/dist/scaffolds/notis-journal/packages/sdk/package.json +0 -36
- package/dist/scaffolds/notis-journal/packages/sdk/src/components/DocumentEditor.tsx +0 -93
- package/dist/scaffolds/notis-journal/packages/sdk/src/components/Markdown.tsx +0 -60
- package/dist/scaffolds/notis-journal/packages/sdk/src/components/MultiSelectActionBar.tsx +0 -278
- package/dist/scaffolds/notis-journal/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -91
- package/dist/scaffolds/notis-journal/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -39
- package/dist/scaffolds/notis-journal/packages/sdk/src/config.ts +0 -196
- package/dist/scaffolds/notis-journal/packages/sdk/src/documents.ts +0 -229
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useBackend.ts +0 -41
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useDocument.ts +0 -78
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useDocuments.ts +0 -121
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useMultiSelect.ts +0 -539
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useNotis.ts +0 -34
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useNotisNavigation.ts +0 -49
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useTool.ts +0 -64
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useTools.ts +0 -56
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
- package/dist/scaffolds/notis-journal/packages/sdk/src/hooks/useUpsertDocument.ts +0 -95
- package/dist/scaffolds/notis-journal/packages/sdk/src/index.ts +0 -83
- package/dist/scaffolds/notis-journal/packages/sdk/src/provider.tsx +0 -43
- package/dist/scaffolds/notis-journal/packages/sdk/src/runtime.ts +0 -220
- package/dist/scaffolds/notis-journal/packages/sdk/src/styles.css +0 -186
- package/dist/scaffolds/notis-journal/packages/sdk/src/ui.ts +0 -15
- package/dist/scaffolds/notis-journal/packages/sdk/src/vite.ts +0 -56
- package/dist/scaffolds/notis-journal/packages/sdk/tsconfig.json +0 -15
- package/dist/scaffolds/notis-journal/postcss.config.mjs +0 -8
- package/dist/scaffolds/notis-journal/skills/journal-onboarding/SKILL.md +0 -120
- package/dist/scaffolds/notis-journal/src/dev-main.tsx +0 -58
- package/dist/scaffolds/notis-journal/src/mock-runtime.ts +0 -197
- package/dist/scaffolds/notis-journal/tailwind.config.ts +0 -58
- package/dist/scaffolds/notis-journal/tsconfig.json +0 -23
- package/dist/scaffolds/notis-journal/vite.config.ts +0 -10
- package/dist/scaffolds/notis-notes/CHANGELOG.md +0 -5
- package/dist/scaffolds/notis-notes/app/globals.css +0 -3
- package/dist/scaffolds/notis-notes/app/layout.tsx +0 -6
- package/dist/scaffolds/notis-notes/app/page.tsx +0 -1943
- package/dist/scaffolds/notis-notes/app/phosphor-icons.ts +0 -596
- package/dist/scaffolds/notis-notes/components/ui/badge.tsx +0 -28
- package/dist/scaffolds/notis-notes/components/ui/button.tsx +0 -53
- package/dist/scaffolds/notis-notes/components/ui/card.tsx +0 -56
- package/dist/scaffolds/notis-notes/components.json +0 -20
- package/dist/scaffolds/notis-notes/lib/utils.ts +0 -6
- package/dist/scaffolds/notis-notes/lib/visible-properties.ts +0 -144
- package/dist/scaffolds/notis-notes/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-notes/metadata/screenshot-fixtures.json +0 -752
- package/dist/scaffolds/notis-notes/notis.config.ts +0 -80
- package/dist/scaffolds/notis-notes/package-lock.json +0 -4636
- package/dist/scaffolds/notis-notes/package.json +0 -35
- package/dist/scaffolds/notis-notes/packages/sdk/package.json +0 -36
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/DocumentEditor.tsx +0 -93
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/Markdown.tsx +0 -60
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectActionBar.tsx +0 -278
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -91
- package/dist/scaffolds/notis-notes/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -39
- package/dist/scaffolds/notis-notes/packages/sdk/src/config.ts +0 -196
- package/dist/scaffolds/notis-notes/packages/sdk/src/documents.ts +0 -229
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useBackend.ts +0 -41
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocument.ts +0 -78
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useDocuments.ts +0 -121
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useMultiSelect.ts +0 -539
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotis.ts +0 -34
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useNotisNavigation.ts +0 -49
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTool.ts +0 -64
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTools.ts +0 -56
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
- package/dist/scaffolds/notis-notes/packages/sdk/src/hooks/useUpsertDocument.ts +0 -95
- package/dist/scaffolds/notis-notes/packages/sdk/src/index.ts +0 -83
- package/dist/scaffolds/notis-notes/packages/sdk/src/provider.tsx +0 -43
- package/dist/scaffolds/notis-notes/packages/sdk/src/runtime.ts +0 -220
- package/dist/scaffolds/notis-notes/packages/sdk/src/styles.css +0 -186
- package/dist/scaffolds/notis-notes/packages/sdk/src/ui.ts +0 -15
- package/dist/scaffolds/notis-notes/packages/sdk/src/vite.ts +0 -56
- package/dist/scaffolds/notis-notes/packages/sdk/tsconfig.json +0 -15
- package/dist/scaffolds/notis-notes/postcss.config.mjs +0 -8
- package/dist/scaffolds/notis-notes/tailwind.config.ts +0 -58
- package/dist/scaffolds/notis-notes/tsconfig.json +0 -23
- package/dist/scaffolds/notis-notes/vite.config.ts +0 -10
- package/dist/scaffolds/notis-random/CHANGELOG.md +0 -15
- package/dist/scaffolds/notis-random/README.md +0 -33
- package/dist/scaffolds/notis-random/app/globals.css +0 -11
- package/dist/scaffolds/notis-random/app/history/page.tsx +0 -67
- package/dist/scaffolds/notis-random/app/layout.tsx +0 -7
- package/dist/scaffolds/notis-random/app/page.tsx +0 -289
- package/dist/scaffolds/notis-random/components/ui/button.tsx +0 -50
- package/dist/scaffolds/notis-random/components/ui/card.tsx +0 -16
- package/dist/scaffolds/notis-random/components/ui/input.tsx +0 -23
- package/dist/scaffolds/notis-random/components.json +0 -20
- package/dist/scaffolds/notis-random/index.html +0 -12
- package/dist/scaffolds/notis-random/lib/notis-tools.ts +0 -128
- package/dist/scaffolds/notis-random/lib/rng.ts +0 -202
- package/dist/scaffolds/notis-random/lib/roll-record.ts +0 -189
- package/dist/scaffolds/notis-random/lib/utils.ts +0 -25
- package/dist/scaffolds/notis-random/metadata/screenshot-1.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-2.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-3.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-4.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-5.png +0 -0
- package/dist/scaffolds/notis-random/metadata/screenshot-fixtures.json +0 -753
- package/dist/scaffolds/notis-random/notis.config.ts +0 -86
- package/dist/scaffolds/notis-random/package-lock.json +0 -4513
- package/dist/scaffolds/notis-random/package.json +0 -36
- package/dist/scaffolds/notis-random/packages/sdk/package.json +0 -36
- package/dist/scaffolds/notis-random/packages/sdk/src/components/DocumentEditor.tsx +0 -93
- package/dist/scaffolds/notis-random/packages/sdk/src/components/Markdown.tsx +0 -60
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectActionBar.tsx +0 -278
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectCheckbox.tsx +0 -91
- package/dist/scaffolds/notis-random/packages/sdk/src/components/MultiSelectDragOverlay.tsx +0 -39
- package/dist/scaffolds/notis-random/packages/sdk/src/config.ts +0 -196
- package/dist/scaffolds/notis-random/packages/sdk/src/documents.ts +0 -229
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useBackend.ts +0 -41
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDatabaseSchema.ts +0 -85
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocument.ts +0 -78
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useDocuments.ts +0 -121
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useMultiSelect.ts +0 -539
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotis.ts +0 -34
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useNotisNavigation.ts +0 -49
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTool.ts +0 -64
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTools.ts +0 -56
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useTopBarSearch.ts +0 -73
- package/dist/scaffolds/notis-random/packages/sdk/src/hooks/useUpsertDocument.ts +0 -95
- package/dist/scaffolds/notis-random/packages/sdk/src/index.ts +0 -83
- package/dist/scaffolds/notis-random/packages/sdk/src/provider.tsx +0 -43
- package/dist/scaffolds/notis-random/packages/sdk/src/runtime.ts +0 -220
- package/dist/scaffolds/notis-random/packages/sdk/src/styles.css +0 -186
- package/dist/scaffolds/notis-random/packages/sdk/src/ui.ts +0 -15
- package/dist/scaffolds/notis-random/packages/sdk/src/vite.ts +0 -56
- package/dist/scaffolds/notis-random/packages/sdk/tsconfig.json +0 -15
- package/dist/scaffolds/notis-random/postcss.config.mjs +0 -6
- package/dist/scaffolds/notis-random/src/dev-main.tsx +0 -70
- package/dist/scaffolds/notis-random/src/mock-runtime.ts +0 -129
- package/dist/scaffolds/notis-random/tailwind.config.ts +0 -50
- package/dist/scaffolds/notis-random/tsconfig.json +0 -23
- package/dist/scaffolds/notis-random/vite.config.ts +0 -11
- package/dist/scaffolds.json +0 -49
- package/template/metadata/screenshot-1.png +0 -0
- package/template/metadata/screenshot-2.png +0 -0
- package/template/metadata/screenshot-3.png +0 -0
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local git inspection for `notis handover`.
|
|
3
|
+
*
|
|
4
|
+
* The CLI has no other reason to know about git, so this stays deliberately
|
|
5
|
+
* small: read where we are, push the branch, and report what the remote is.
|
|
6
|
+
* Everything else about the repository is the cloud workspace's problem.
|
|
7
|
+
*
|
|
8
|
+
* Every call is `spawnSync` on the real `git` binary rather than a library.
|
|
9
|
+
* The user's credentials, hooks, SSH agent and includeIf config are what make a
|
|
10
|
+
* push succeed on their machine, and only their own git honors all of them.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { lstatSync, readFileSync } from 'node:fs';
|
|
15
|
+
import { basename, relative, resolve, sep } from 'node:path';
|
|
16
|
+
import { CliError, EXIT_CODES } from './errors.js';
|
|
17
|
+
|
|
18
|
+
const GIT_TIMEOUT_MS = 120_000;
|
|
19
|
+
const MAX_SECRET_SCAN_BYTES = 1_000_000;
|
|
20
|
+
const SAFE_ENV_TEMPLATES = /^\.env\.(?:example|sample|template)$/i;
|
|
21
|
+
const SENSITIVE_PATH = /^(?:\.env(?:\..+)?|\.envrc|\.git-credentials|\.npmrc|\.pypirc|\.netrc|credentials(?:\..+)?|secrets?(?:\..+)?|id_(?:rsa|dsa|ecdsa|ed25519)(?:\.pub)?|.*\.(?:pem|key|p12|pfx|jks))$/i;
|
|
22
|
+
const SENSITIVE_CONTENT = [
|
|
23
|
+
/-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----/,
|
|
24
|
+
/\b[a-z][a-z0-9+.-]*:\/\/[^/\s:@]+:[^/\s@]+@/i,
|
|
25
|
+
/\bAKIA[0-9A-Z]{16}\b/,
|
|
26
|
+
/\bgh[pousr]_[A-Za-z0-9]{36,}\b/,
|
|
27
|
+
/\bsk-[A-Za-z0-9_-]{20,}\b/,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
export function runGit(
|
|
31
|
+
args,
|
|
32
|
+
{ cwd = process.cwd(), timeoutMs = GIT_TIMEOUT_MS, trimOutput = true } = {},
|
|
33
|
+
) {
|
|
34
|
+
const result = spawnSync('git', args, {
|
|
35
|
+
cwd,
|
|
36
|
+
encoding: 'utf8',
|
|
37
|
+
timeout: timeoutMs,
|
|
38
|
+
env: {
|
|
39
|
+
...process.env,
|
|
40
|
+
// A push that stops to ask for a password would hang a non-interactive
|
|
41
|
+
// agent run forever. Fail fast instead and let the hint explain.
|
|
42
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
if (result.error && result.error.code === 'ENOENT') {
|
|
46
|
+
throw new CliError({
|
|
47
|
+
code: 'git_not_found',
|
|
48
|
+
message: 'git is not installed or not on PATH.',
|
|
49
|
+
exitCode: EXIT_CODES.usage,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
exitCode: result.status ?? 1,
|
|
54
|
+
stdout: trimOutput ? (result.stdout || '').trim() : (result.stdout || ''),
|
|
55
|
+
stderr: trimOutput ? (result.stderr || '').trim() : (result.stderr || ''),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function gitOrNull(args, options) {
|
|
60
|
+
const result = runGit(args, options);
|
|
61
|
+
return result.exitCode === 0 ? result.stdout : null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function nulSeparatedGitPaths(args, repository) {
|
|
65
|
+
const result = runGit([...args, '-z'], { cwd: repository.toplevel, trimOutput: false });
|
|
66
|
+
if (result.exitCode !== 0 || !result.stdout) return [];
|
|
67
|
+
return result.stdout.split('\0').filter(Boolean);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Exact files `git add -A` would include, expanding untracked directories. */
|
|
71
|
+
function filesToAutoCommit(repository) {
|
|
72
|
+
return [...new Set([
|
|
73
|
+
...nulSeparatedGitPaths(['diff', '--name-only'], repository),
|
|
74
|
+
...nulSeparatedGitPaths(['diff', '--cached', '--name-only'], repository),
|
|
75
|
+
...nulSeparatedGitPaths(['ls-files', '--others', '--exclude-standard'], repository),
|
|
76
|
+
])];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Refuse files that are unsafe to publish automatically without user review. */
|
|
80
|
+
export function sensitiveAutoCommitFiles(repository) {
|
|
81
|
+
const root = resolve(repository.toplevel);
|
|
82
|
+
const sensitive = [];
|
|
83
|
+
for (const path of filesToAutoCommit(repository)) {
|
|
84
|
+
const absolute = resolve(root, path);
|
|
85
|
+
const insideRoot = relative(root, absolute);
|
|
86
|
+
if (insideRoot === '..' || insideRoot.startsWith(`..${sep}`) || insideRoot === '') continue;
|
|
87
|
+
const name = basename(path);
|
|
88
|
+
if (SENSITIVE_PATH.test(name) && !SAFE_ENV_TEMPLATES.test(name)) {
|
|
89
|
+
sensitive.push(path);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
const stat = lstatSync(absolute);
|
|
94
|
+
if (!stat.isFile() || stat.size > MAX_SECRET_SCAN_BYTES) continue;
|
|
95
|
+
const content = readFileSync(absolute, 'utf8');
|
|
96
|
+
if (SENSITIVE_CONTENT.some((pattern) => pattern.test(content))) sensitive.push(path);
|
|
97
|
+
} catch {
|
|
98
|
+
// Deleted files and paths racing with an editor have no content to leak.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return sensitive;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Parse an origin URL into {owner, repo}. Handles the three forms git remotes
|
|
106
|
+
* actually take: scp-style ssh, ssh:// and https://.
|
|
107
|
+
*/
|
|
108
|
+
export function parseRemoteUrl(url) {
|
|
109
|
+
if (typeof url !== 'string' || !url) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const trimmed = url.trim().replace(/\.git$/, '');
|
|
113
|
+
const scp = trimmed.match(/^[^@]+@([^:]+):(.+)$/);
|
|
114
|
+
const path = scp ? scp[2] : trimmed.replace(/^[a-z+]+:\/\/(?:[^@/]+@)?[^/]+\//i, '');
|
|
115
|
+
const host = scp ? scp[1] : (trimmed.match(/^[a-z+]+:\/\/(?:[^@/]+@)?([^/]+)/i) || [])[1];
|
|
116
|
+
const segments = path.split('/').filter(Boolean);
|
|
117
|
+
if (segments.length < 2) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
host: host || null,
|
|
122
|
+
owner: segments[segments.length - 2],
|
|
123
|
+
repo: segments[segments.length - 1],
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Everything `handover start` needs to know about where it is running. */
|
|
128
|
+
export function inspectRepository(cwd = process.cwd()) {
|
|
129
|
+
const toplevel = gitOrNull(['rev-parse', '--show-toplevel'], { cwd });
|
|
130
|
+
if (!toplevel) {
|
|
131
|
+
throw new CliError({
|
|
132
|
+
code: 'not_a_git_repository',
|
|
133
|
+
message: 'Hand-over runs from inside a git repository.',
|
|
134
|
+
exitCode: EXIT_CODES.usage,
|
|
135
|
+
hints: [{ message: 'cd into the repository you want Notis to work on, then run the command again.' }],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const branch = gitOrNull(['branch', '--show-current'], { cwd: toplevel });
|
|
140
|
+
if (!branch) {
|
|
141
|
+
throw new CliError({
|
|
142
|
+
code: 'detached_head',
|
|
143
|
+
message: 'HEAD is detached, so there is no branch to hand over.',
|
|
144
|
+
exitCode: EXIT_CODES.usage,
|
|
145
|
+
hints: [{ message: 'Check out a branch first: git switch -c my-feature' }],
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const remoteUrl = gitOrNull(['remote', 'get-url', 'origin'], { cwd: toplevel });
|
|
150
|
+
if (!remoteUrl) {
|
|
151
|
+
throw new CliError({
|
|
152
|
+
code: 'no_origin_remote',
|
|
153
|
+
message: 'This repository has no "origin" remote, so the cloud agent cannot fetch the branch.',
|
|
154
|
+
exitCode: EXIT_CODES.usage,
|
|
155
|
+
hints: [{ message: 'Add one: git remote add origin <url>' }],
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const status = runGit(['status', '--porcelain'], { cwd: toplevel });
|
|
160
|
+
const dirtyFiles = status.stdout
|
|
161
|
+
? status.stdout.split('\n').map((line) => line.slice(3).trim()).filter(Boolean)
|
|
162
|
+
: [];
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
toplevel,
|
|
166
|
+
branch,
|
|
167
|
+
remoteUrl,
|
|
168
|
+
remote: parseRemoteUrl(remoteUrl),
|
|
169
|
+
dirtyFiles,
|
|
170
|
+
head: gitOrNull(['rev-parse', 'HEAD'], { cwd: toplevel }),
|
|
171
|
+
upstream: gitOrNull(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'], {
|
|
172
|
+
cwd: toplevel,
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Commit everything in the working tree, including untracked files. */
|
|
178
|
+
export function commitWorkingTree(repository, message) {
|
|
179
|
+
const sensitiveFiles = sensitiveAutoCommitFiles(repository);
|
|
180
|
+
if (sensitiveFiles.length) {
|
|
181
|
+
throw new CliError({
|
|
182
|
+
code: 'sensitive_working_tree',
|
|
183
|
+
message: 'Refusing to publish files that may contain credentials or private keys.',
|
|
184
|
+
exitCode: EXIT_CODES.conflict,
|
|
185
|
+
details: { sensitive_files: sensitiveFiles.slice(0, 20) },
|
|
186
|
+
hints: [
|
|
187
|
+
{ message: 'Review, remove, or ignore these files before handing over.' },
|
|
188
|
+
{ message: 'To publish them deliberately, commit and push them yourself first.' },
|
|
189
|
+
],
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const add = runGit(['add', '-A'], { cwd: repository.toplevel });
|
|
193
|
+
if (add.exitCode !== 0) {
|
|
194
|
+
throw new CliError({
|
|
195
|
+
code: 'git_add_failed',
|
|
196
|
+
message: `Could not stage the working tree: ${add.stderr || add.stdout}`,
|
|
197
|
+
exitCode: EXIT_CODES.unexpected,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
const commit = runGit(['commit', '-m', message], { cwd: repository.toplevel });
|
|
201
|
+
if (commit.exitCode !== 0) {
|
|
202
|
+
throw new CliError({
|
|
203
|
+
code: 'git_commit_failed',
|
|
204
|
+
message: `Could not commit the working tree: ${commit.stderr || commit.stdout}`,
|
|
205
|
+
exitCode: EXIT_CODES.unexpected,
|
|
206
|
+
hints: [{ message: 'Commit the changes yourself, then run the hand-over again.' }],
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return gitOrNull(['rev-parse', 'HEAD'], { cwd: repository.toplevel });
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Push the branch to origin. The cloud workspace fetches from origin, so an
|
|
214
|
+
* unpushed commit simply does not exist as far as the hand-over is concerned.
|
|
215
|
+
*/
|
|
216
|
+
export function pushBranch(repository, branch) {
|
|
217
|
+
const args = repository.upstream
|
|
218
|
+
? ['push', 'origin', branch]
|
|
219
|
+
: ['push', '--set-upstream', 'origin', branch];
|
|
220
|
+
const result = runGit(args, { cwd: repository.toplevel });
|
|
221
|
+
if (result.exitCode !== 0) {
|
|
222
|
+
throw new CliError({
|
|
223
|
+
code: 'git_push_failed',
|
|
224
|
+
message: `Could not push ${branch} to origin: ${result.stderr || result.stdout}`,
|
|
225
|
+
exitCode: EXIT_CODES.conflict,
|
|
226
|
+
hints: [
|
|
227
|
+
{ message: 'The cloud agent works from origin, so the branch has to be pushed first.' },
|
|
228
|
+
{ message: 'If the remote moved ahead, reconcile locally (git pull --rebase) and retry.' },
|
|
229
|
+
],
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Entry point for the detached process that owns an OAuth loopback callback.
|
|
3
|
+
//
|
|
4
|
+
// Spawned by `notis login` / `notis start` whenever the calling process cannot
|
|
5
|
+
// wait for the browser itself — an agent reads a command's output only after it
|
|
6
|
+
// exits, so the command has to return the authorization URL while something
|
|
7
|
+
// else keeps listening. Never run this by hand: it takes a single argument, the
|
|
8
|
+
// path to a short-lived payload file the parent wrote and this process deletes.
|
|
9
|
+
import { runDetachedLoginListener } from './oauth.js';
|
|
10
|
+
|
|
11
|
+
process.exitCode = await runDetachedLoginListener(
|
|
12
|
+
process.argv[2],
|
|
13
|
+
undefined,
|
|
14
|
+
process.argv[3],
|
|
15
|
+
);
|